Merge tag 'batadv-net-for-davem-20191025' of git://git.open-mesh.org/linux-merge
Simon Wunderlich says: ==================== Here are two batman-adv bugfixes: * Fix free/alloc race for OGM and OGMv2, by Sven Eckelmann (2 patches) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
@@ -193,14 +195,18 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
|
||||
unsigned char *ogm_buff;
|
||||
u32 random_seqno;
|
||||
|
||||
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
/* randomize initial seqno to avoid collision */
|
||||
get_random_bytes(&random_seqno, sizeof(random_seqno));
|
||||
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
|
||||
|
||||
hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
|
||||
ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
|
||||
if (!ogm_buff)
|
||||
if (!ogm_buff) {
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hard_iface->bat_iv.ogm_buff = ogm_buff;
|
||||
|
||||
@@ -212,35 +218,59 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
|
||||
batadv_ogm_packet->reserved = 0;
|
||||
batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
|
||||
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
kfree(hard_iface->bat_iv.ogm_buff);
|
||||
hard_iface->bat_iv.ogm_buff = NULL;
|
||||
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_ogm_packet *batadv_ogm_packet;
|
||||
unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
|
||||
void *ogm_buff;
|
||||
|
||||
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
|
||||
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
ogm_buff = hard_iface->bat_iv.ogm_buff;
|
||||
if (!ogm_buff)
|
||||
goto unlock;
|
||||
|
||||
batadv_ogm_packet = ogm_buff;
|
||||
ether_addr_copy(batadv_ogm_packet->orig,
|
||||
hard_iface->net_dev->dev_addr);
|
||||
ether_addr_copy(batadv_ogm_packet->prev_sender,
|
||||
hard_iface->net_dev->dev_addr);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_ogm_packet *batadv_ogm_packet;
|
||||
unsigned char *ogm_buff = hard_iface->bat_iv.ogm_buff;
|
||||
void *ogm_buff;
|
||||
|
||||
batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
|
||||
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
ogm_buff = hard_iface->bat_iv.ogm_buff;
|
||||
if (!ogm_buff)
|
||||
goto unlock;
|
||||
|
||||
batadv_ogm_packet = ogm_buff;
|
||||
batadv_ogm_packet->ttl = BATADV_TTL;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
/* when do we schedule our own ogm to be sent */
|
||||
@@ -742,7 +772,11 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
|
||||
}
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
||||
/**
|
||||
* batadv_iv_ogm_schedule_buff() - schedule submission of hardif ogm buffer
|
||||
* @hard_iface: interface whose ogm buffer should be transmitted
|
||||
*/
|
||||
static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
|
||||
@@ -753,9 +787,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
||||
u16 tvlv_len = 0;
|
||||
unsigned long send_time;
|
||||
|
||||
if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
|
||||
hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
|
||||
return;
|
||||
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
|
||||
/* the interface gets activated here to avoid race conditions between
|
||||
* the moment of activating the interface in
|
||||
@@ -823,6 +855,17 @@ out:
|
||||
batadv_hardif_put(primary_if);
|
||||
}
|
||||
|
||||
static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
|
||||
hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
|
||||
return;
|
||||
|
||||
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
batadv_iv_ogm_schedule_buff(hard_iface);
|
||||
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over iterface
|
||||
* @orig_node: originator which reproadcasted the OGMs directly
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/rculist.h>
|
||||
@@ -256,14 +257,12 @@ static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_ogm_send() - periodic worker broadcasting the own OGM
|
||||
* @work: work queue item
|
||||
* batadv_v_ogm_send_softif() - periodic worker broadcasting the own OGM
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
*/
|
||||
static void batadv_v_ogm_send(struct work_struct *work)
|
||||
static void batadv_v_ogm_send_softif(struct batadv_priv *bat_priv)
|
||||
{
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
struct batadv_priv_bat_v *bat_v;
|
||||
struct batadv_priv *bat_priv;
|
||||
struct batadv_ogm2_packet *ogm_packet;
|
||||
struct sk_buff *skb, *skb_tmp;
|
||||
unsigned char *ogm_buff;
|
||||
@@ -271,8 +270,7 @@ static void batadv_v_ogm_send(struct work_struct *work)
|
||||
u16 tvlv_len = 0;
|
||||
int ret;
|
||||
|
||||
bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
|
||||
bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
|
||||
lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
|
||||
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
||||
goto out;
|
||||
@@ -363,6 +361,23 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_ogm_send() - periodic worker broadcasting the own OGM
|
||||
* @work: work queue item
|
||||
*/
|
||||
static void batadv_v_ogm_send(struct work_struct *work)
|
||||
{
|
||||
struct batadv_priv_bat_v *bat_v;
|
||||
struct batadv_priv *bat_priv;
|
||||
|
||||
bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
|
||||
bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
|
||||
|
||||
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
batadv_v_ogm_send_softif(bat_priv);
|
||||
mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
|
||||
* @work: work queue item
|
||||
@@ -424,11 +439,15 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface)
|
||||
struct batadv_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
|
||||
struct batadv_ogm2_packet *ogm_packet;
|
||||
|
||||
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
if (!bat_priv->bat_v.ogm_buff)
|
||||
return;
|
||||
goto unlock;
|
||||
|
||||
ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
|
||||
ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1050,6 +1069,8 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv)
|
||||
atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
|
||||
INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
|
||||
|
||||
mutex_init(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1061,7 +1082,11 @@ void batadv_v_ogm_free(struct batadv_priv *bat_priv)
|
||||
{
|
||||
cancel_delayed_work_sync(&bat_priv->bat_v.ogm_wq);
|
||||
|
||||
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
|
||||
kfree(bat_priv->bat_v.ogm_buff);
|
||||
bat_priv->bat_v.ogm_buff = NULL;
|
||||
bat_priv->bat_v.ogm_buff_len = 0;
|
||||
|
||||
mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <linux/kref.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/rculist.h>
|
||||
@@ -929,6 +930,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
|
||||
INIT_LIST_HEAD(&hard_iface->list);
|
||||
INIT_HLIST_HEAD(&hard_iface->neigh_list);
|
||||
|
||||
mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||
spin_lock_init(&hard_iface->neigh_list_lock);
|
||||
kref_init(&hard_iface->refcount);
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/sched.h> /* for linux/wait.h */
|
||||
@@ -81,6 +82,9 @@ struct batadv_hard_iface_bat_iv {
|
||||
|
||||
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
|
||||
atomic_t ogm_seqno;
|
||||
|
||||
/** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
|
||||
struct mutex ogm_buff_mutex;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1539,6 +1543,9 @@ struct batadv_priv_bat_v {
|
||||
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
|
||||
atomic_t ogm_seqno;
|
||||
|
||||
/** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */
|
||||
struct mutex ogm_buff_mutex;
|
||||
|
||||
/** @ogm_wq: workqueue used to schedule OGM transmissions */
|
||||
struct delayed_work ogm_wq;
|
||||
};
|
||||
|
Reference in New Issue
Block a user