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/kernel.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/pkt_sched.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;
|
unsigned char *ogm_buff;
|
||||||
u32 random_seqno;
|
u32 random_seqno;
|
||||||
|
|
||||||
|
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||||
|
|
||||||
/* randomize initial seqno to avoid collision */
|
/* randomize initial seqno to avoid collision */
|
||||||
get_random_bytes(&random_seqno, sizeof(random_seqno));
|
get_random_bytes(&random_seqno, sizeof(random_seqno));
|
||||||
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
|
atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
|
||||||
|
|
||||||
hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
|
hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN;
|
||||||
ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC);
|
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;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
hard_iface->bat_iv.ogm_buff = ogm_buff;
|
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->reserved = 0;
|
||||||
batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
|
batadv_ogm_packet->tq = BATADV_TQ_MAX_VALUE;
|
||||||
|
|
||||||
|
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
|
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);
|
kfree(hard_iface->bat_iv.ogm_buff);
|
||||||
hard_iface->bat_iv.ogm_buff = NULL;
|
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)
|
static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||||
{
|
{
|
||||||
struct batadv_ogm_packet *batadv_ogm_packet;
|
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,
|
ether_addr_copy(batadv_ogm_packet->orig,
|
||||||
hard_iface->net_dev->dev_addr);
|
hard_iface->net_dev->dev_addr);
|
||||||
ether_addr_copy(batadv_ogm_packet->prev_sender,
|
ether_addr_copy(batadv_ogm_packet->prev_sender,
|
||||||
hard_iface->net_dev->dev_addr);
|
hard_iface->net_dev->dev_addr);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
|
batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface)
|
||||||
{
|
{
|
||||||
struct batadv_ogm_packet *batadv_ogm_packet;
|
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;
|
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 */
|
/* 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);
|
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||||
unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff;
|
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;
|
u16 tvlv_len = 0;
|
||||||
unsigned long send_time;
|
unsigned long send_time;
|
||||||
|
|
||||||
if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
|
lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex);
|
||||||
hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* the interface gets activated here to avoid race conditions between
|
/* the interface gets activated here to avoid race conditions between
|
||||||
* the moment of activating the interface in
|
* the moment of activating the interface in
|
||||||
@@ -823,6 +855,17 @@ out:
|
|||||||
batadv_hardif_put(primary_if);
|
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
|
* batadv_iv_orig_ifinfo_sum() - Get bcast_own sum for originator over iterface
|
||||||
* @orig_node: originator which reproadcasted the OGMs directly
|
* @orig_node: originator which reproadcasted the OGMs directly
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/lockdep.h>
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/rculist.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
|
* batadv_v_ogm_send_softif() - periodic worker broadcasting the own OGM
|
||||||
* @work: work queue item
|
* @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_hard_iface *hard_iface;
|
||||||
struct batadv_priv_bat_v *bat_v;
|
|
||||||
struct batadv_priv *bat_priv;
|
|
||||||
struct batadv_ogm2_packet *ogm_packet;
|
struct batadv_ogm2_packet *ogm_packet;
|
||||||
struct sk_buff *skb, *skb_tmp;
|
struct sk_buff *skb, *skb_tmp;
|
||||||
unsigned char *ogm_buff;
|
unsigned char *ogm_buff;
|
||||||
@@ -271,8 +270,7 @@ static void batadv_v_ogm_send(struct work_struct *work)
|
|||||||
u16 tvlv_len = 0;
|
u16 tvlv_len = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
|
lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
|
||||||
bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
|
|
||||||
|
|
||||||
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -363,6 +361,23 @@ out:
|
|||||||
return;
|
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
|
* batadv_v_ogm_aggr_work() - OGM queue periodic task per interface
|
||||||
* @work: work queue item
|
* @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_priv *bat_priv = netdev_priv(primary_iface->soft_iface);
|
||||||
struct batadv_ogm2_packet *ogm_packet;
|
struct batadv_ogm2_packet *ogm_packet;
|
||||||
|
|
||||||
|
mutex_lock(&bat_priv->bat_v.ogm_buff_mutex);
|
||||||
if (!bat_priv->bat_v.ogm_buff)
|
if (!bat_priv->bat_v.ogm_buff)
|
||||||
return;
|
goto unlock;
|
||||||
|
|
||||||
ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
|
ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff;
|
||||||
ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr);
|
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);
|
atomic_set(&bat_priv->bat_v.ogm_seqno, random_seqno);
|
||||||
INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
|
INIT_DELAYED_WORK(&bat_priv->bat_v.ogm_wq, batadv_v_ogm_send);
|
||||||
|
|
||||||
|
mutex_init(&bat_priv->bat_v.ogm_buff_mutex);
|
||||||
|
|
||||||
return 0;
|
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);
|
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);
|
kfree(bat_priv->bat_v.ogm_buff);
|
||||||
bat_priv->bat_v.ogm_buff = NULL;
|
bat_priv->bat_v.ogm_buff = NULL;
|
||||||
bat_priv->bat_v.ogm_buff_len = 0;
|
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/kref.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
#include <linux/rculist.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_LIST_HEAD(&hard_iface->list);
|
||||||
INIT_HLIST_HEAD(&hard_iface->neigh_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);
|
spin_lock_init(&hard_iface->neigh_list_lock);
|
||||||
kref_init(&hard_iface->refcount);
|
kref_init(&hard_iface->refcount);
|
||||||
|
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/sched.h> /* for linux/wait.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 */
|
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
|
||||||
atomic_t ogm_seqno;
|
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 */
|
/** @ogm_seqno: OGM sequence number - used to identify each OGM */
|
||||||
atomic_t ogm_seqno;
|
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 */
|
/** @ogm_wq: workqueue used to schedule OGM transmissions */
|
||||||
struct delayed_work ogm_wq;
|
struct delayed_work ogm_wq;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user