Commit 55793d2a authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 0a29ac5b 40e220b4
...@@ -22,6 +22,8 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) ...@@ -823,6 +855,17 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
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 @@ ...@@ -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, ...@@ -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) ...@@ -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 @@ static void batadv_v_ogm_send(struct work_struct *work) ...@@ -363,6 +361,23 @@ static void batadv_v_ogm_send(struct work_struct *work)
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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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;
}; };
......
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