--- /dev/null
+From: Eric Dumazet <edumazet@google.com>
+Date: Mon, 12 Aug 2019 04:57:27 -0700
+Subject: batman-adv: fix uninit-value in batadv_netlink_get_ifindex()
+
+batadv_netlink_get_ifindex() needs to make sure user passed
+a correct u32 attribute.
+
+syzbot reported :
+BUG: KMSAN: uninit-value in batadv_netlink_dump_hardif+0x70d/0x880 net/batman-adv/netlink.c:968
+CPU: 1 PID: 11705 Comm: syz-executor888 Not tainted 5.1.0+ #1
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+Call Trace:
+ __dump_stack lib/dump_stack.c:77 [inline]
+ dump_stack+0x191/0x1f0 lib/dump_stack.c:113
+ kmsan_report+0x130/0x2a0 mm/kmsan/kmsan.c:622
+ __msan_warning+0x75/0xe0 mm/kmsan/kmsan_instr.c:310
+ batadv_netlink_dump_hardif+0x70d/0x880 net/batman-adv/netlink.c:968
+ genl_lock_dumpit+0xc6/0x130 net/netlink/genetlink.c:482
+ netlink_dump+0xa84/0x1ab0 net/netlink/af_netlink.c:2253
+ __netlink_dump_start+0xa3a/0xb30 net/netlink/af_netlink.c:2361
+ genl_family_rcv_msg net/netlink/genetlink.c:550 [inline]
+ genl_rcv_msg+0xfc1/0x1a40 net/netlink/genetlink.c:627
+ netlink_rcv_skb+0x431/0x620 net/netlink/af_netlink.c:2486
+ genl_rcv+0x63/0x80 net/netlink/genetlink.c:638
+ netlink_unicast_kernel net/netlink/af_netlink.c:1311 [inline]
+ netlink_unicast+0xf3e/0x1020 net/netlink/af_netlink.c:1337
+ netlink_sendmsg+0x127e/0x12f0 net/netlink/af_netlink.c:1926
+ sock_sendmsg_nosec net/socket.c:651 [inline]
+ sock_sendmsg net/socket.c:661 [inline]
+ ___sys_sendmsg+0xcc6/0x1200 net/socket.c:2260
+ __sys_sendmsg net/socket.c:2298 [inline]
+ __do_sys_sendmsg net/socket.c:2307 [inline]
+ __se_sys_sendmsg+0x305/0x460 net/socket.c:2305
+ __x64_sys_sendmsg+0x4a/0x70 net/socket.c:2305
+ do_syscall_64+0xbc/0xf0 arch/x86/entry/common.c:291
+ entry_SYSCALL_64_after_hwframe+0x63/0xe7
+RIP: 0033:0x440209
+
+Fixes: 55d368c3a57e ("batman-adv: netlink: hardif query")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Reported-by: syzbot <syzkaller@googlegroups.com>
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/9b470b8a2b9ef4ce68d6e95febd3a0574be1ac14
+
+diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
+index 0d9459b69bdb812b1b68e28e6b68fec8ec95df2d..c32820963b8e706b4cdde10d46ec582bc51ec4eb 100644
+--- a/net/batman-adv/netlink.c
++++ b/net/batman-adv/netlink.c
+@@ -118,7 +118,7 @@ batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype)
+ {
+ struct nlattr *attr = nlmsg_find_attr(nlh, GENL_HDRLEN, attrtype);
+
+- return attr ? nla_get_u32(attr) : 0;
++ return (attr && nla_len(attr) == sizeof(u32)) ? nla_get_u32(attr) : 0;
+ }
+
+ /**
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Fri, 23 Aug 2019 14:34:27 +0200
+Subject: batman-adv: Only read OGM tvlv_len after buffer len check
+
+Multiple batadv_ogm_packet can be stored in an skbuff. The functions
+batadv_iv_ogm_send_to_if()/batadv_iv_ogm_receive() use
+batadv_iv_ogm_aggr_packet() to check if there is another additional
+batadv_ogm_packet in the skb or not before they continue processing the
+packet.
+
+The length for such an OGM is BATADV_OGM_HLEN +
+batadv_ogm_packet->tvlv_len. The check must first check that at least
+BATADV_OGM_HLEN bytes are available before it accesses tvlv_len (which is
+part of the header. Otherwise it might try read outside of the currently
+available skbuff to get the content of tvlv_len.
+
+Fixes: 0b6aa0d43767 ("batman-adv: tvlv - basic infrastructure")
+Reported-by: syzbot+355cab184197dbbfa384@syzkaller.appspotmail.com
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+Acked-by: Antonio Quartulli <a@unstable.cc>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/07b6051ebcfaa7ea89b4f278eca2ff4070d29e56
+
+diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
+index 73bf6a93a3cf1141a34657bf1284893199e04db9..3db8a0278046c0a9f4d2604f0067ba4efe3ef588 100644
+--- a/net/batman-adv/bat_iv_ogm.c
++++ b/net/batman-adv/bat_iv_ogm.c
+@@ -463,17 +463,23 @@ static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv)
+ * batadv_iv_ogm_aggr_packet() - checks if there is another OGM attached
+ * @buff_pos: current position in the skb
+ * @packet_len: total length of the skb
+- * @tvlv_len: tvlv length of the previously considered OGM
++ * @ogm_packet: potential OGM in buffer
+ *
+ * Return: true if there is enough space for another OGM, false otherwise.
+ */
+-static bool batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
+- __be16 tvlv_len)
++static bool
++batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len,
++ const struct batadv_ogm_packet *ogm_packet)
+ {
+ int next_buff_pos = 0;
+
+- next_buff_pos += buff_pos + BATADV_OGM_HLEN;
+- next_buff_pos += ntohs(tvlv_len);
++ /* check if there is enough space for the header */
++ next_buff_pos += buff_pos + sizeof(*ogm_packet);
++ if (next_buff_pos > packet_len)
++ return false;
++
++ /* check if there is enough space for the optional TVLV */
++ next_buff_pos += ntohs(ogm_packet->tvlv_len);
+
+ return (next_buff_pos <= packet_len) &&
+ (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
+@@ -501,7 +507,7 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
+
+ /* adjust all flags and log packets */
+ while (batadv_iv_ogm_aggr_packet(buff_pos, forw_packet->packet_len,
+- batadv_ogm_packet->tvlv_len)) {
++ batadv_ogm_packet)) {
+ /* we might have aggregated direct link packets with an
+ * ordinary base packet
+ */
+@@ -1852,7 +1858,7 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
+
+ /* unpack the aggregated packets and process them one by one */
+ while (batadv_iv_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
+- ogm_packet->tvlv_len)) {
++ ogm_packet)) {
+ batadv_iv_ogm_process(skb, ogm_offset, if_incoming);
+
+ ogm_offset += BATADV_OGM_HLEN;
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Fri, 23 Aug 2019 14:34:28 +0200
+Subject: batman-adv: Only read OGM2 tvlv_len after buffer len check
+
+Multiple batadv_ogm2_packet can be stored in an skbuff. The functions
+batadv_v_ogm_send_to_if() uses batadv_v_ogm_aggr_packet() to check if there
+is another additional batadv_ogm2_packet in the skb or not before they
+continue processing the packet.
+
+The length for such an OGM2 is BATADV_OGM2_HLEN +
+batadv_ogm2_packet->tvlv_len. The check must first check that at least
+BATADV_OGM2_HLEN bytes are available before it accesses tvlv_len (which is
+part of the header. Otherwise it might try read outside of the currently
+available skbuff to get the content of tvlv_len.
+
+Fixes: 667996ebeab4 ("batman-adv: OGMv2 - implement originators logic")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/18f77da3761c5550f42a2d131f0fe5cac62e022d
+
+diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
+index 2948b41b06d47c0ee32649fa410b323f39c36151..d241ccc0ca0278173853512c8aa4bfb8b041f996 100644
+--- a/net/batman-adv/bat_v_ogm.c
++++ b/net/batman-adv/bat_v_ogm.c
+@@ -643,17 +643,23 @@ batadv_v_ogm_process_per_outif(struct batadv_priv *bat_priv,
+ * batadv_v_ogm_aggr_packet() - checks if there is another OGM aggregated
+ * @buff_pos: current position in the skb
+ * @packet_len: total length of the skb
+- * @tvlv_len: tvlv length of the previously considered OGM
++ * @ogm2_packet: potential OGM2 in buffer
+ *
+ * Return: true if there is enough space for another OGM, false otherwise.
+ */
+-static bool batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
+- __be16 tvlv_len)
++static bool
++batadv_v_ogm_aggr_packet(int buff_pos, int packet_len,
++ const struct batadv_ogm2_packet *ogm2_packet)
+ {
+ int next_buff_pos = 0;
+
+- next_buff_pos += buff_pos + BATADV_OGM2_HLEN;
+- next_buff_pos += ntohs(tvlv_len);
++ /* check if there is enough space for the header */
++ next_buff_pos += buff_pos + sizeof(*ogm2_packet);
++ if (next_buff_pos > packet_len)
++ return false;
++
++ /* check if there is enough space for the optional TVLV */
++ next_buff_pos += ntohs(ogm2_packet->tvlv_len);
+
+ return (next_buff_pos <= packet_len) &&
+ (next_buff_pos <= BATADV_MAX_AGGREGATION_BYTES);
+@@ -830,7 +836,7 @@ int batadv_v_ogm_packet_recv(struct sk_buff *skb,
+ ogm_packet = (struct batadv_ogm2_packet *)skb->data;
+
+ while (batadv_v_ogm_aggr_packet(ogm_offset, skb_headlen(skb),
+- ogm_packet->tvlv_len)) {
++ ogm_packet)) {
+ batadv_v_ogm_process(skb, ogm_offset, if_incoming);
+
+ ogm_offset += BATADV_OGM2_HLEN;
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Thu, 3 Oct 2019 17:02:01 +0200
+Subject: batman-adv: Avoid free/alloc race when handling OGM2 buffer
+
+A B.A.T.M.A.N. V virtual interface has an OGM2 packet buffer which is
+initialized using data from the RTNL lock protected netdevice notifier and
+other rtnetlink related hooks. It is sent regularly via various slave
+interfaces of the batadv virtual interface and in this process also
+modified (realloced) to integrate additional state information via TVLV
+containers.
+
+It must be avoided that the worker item is executed without a common lock
+with the netdevice notifier/rtnetlink helpers. Otherwise it can either
+happen that half modified data is sent out or the functions modifying the
+OGM2 buffer try to access already freed memory regions.
+
+Fixes: 632835348e65 ("batman-adv: OGMv2 - add basic infrastructure")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/14ee24576213ff02272b7f8d975c7c61d5448aa2
+
+diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
+index d241ccc0ca0278173853512c8aa4bfb8b041f996..a9f949501ff3c354d38e3ad333901310391f27d8 100644
+--- a/net/batman-adv/bat_v_ogm.c
++++ b/net/batman-adv/bat_v_ogm.c
+@@ -33,6 +33,7 @@
+ #include <linux/random.h>
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
++#include <linux/rtnetlink.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+ #include <linux/stddef.h>
+@@ -128,14 +129,12 @@ static void batadv_v_ogm_send_to_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;
+@@ -143,8 +142,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);
++ ASSERT_RTNL();
+
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+ goto out;
+@@ -235,6 +233,22 @@ static void batadv_v_ogm_send(struct work_struct *work)
+ 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;
++
++ rtnl_lock();
++ bat_v = container_of(work, struct batadv_priv_bat_v, ogm_wq.work);
++ bat_priv = container_of(bat_v, struct batadv_priv, bat_v);
++ batadv_v_ogm_send_softif(bat_priv);
++ rtnl_unlock();
++}
++
+ /**
+ * batadv_v_ogm_iface_enable() - prepare an interface for B.A.T.M.A.N. V
+ * @hard_iface: the interface to prepare
+@@ -261,6 +275,8 @@ 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;
+
++ ASSERT_RTNL();
++
+ if (!bat_priv->bat_v.ogm_buff)
+ return;
+
+@@ -869,6 +885,8 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv)
+ unsigned char *ogm_buff;
+ u32 random_seqno;
+
++ ASSERT_RTNL();
++
+ bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
+ ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
+ if (!ogm_buff)
+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
+index 476b052ad9824d4cbcd6218dce40b603e3400fd2..8eaec92aff8919f0c6ca6b05be22e592b7ae0e1a 100644
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -1474,10 +1474,10 @@ struct batadv_softif_vlan {
+ * struct batadv_priv_bat_v - B.A.T.M.A.N. V per soft-interface private data
+ */
+ struct batadv_priv_bat_v {
+- /** @ogm_buff: buffer holding the OGM packet */
++ /** @ogm_buff: buffer holding the OGM packet. rtnl protected */
+ unsigned char *ogm_buff;
+
+- /** @ogm_buff_len: length of the OGM packet buffer */
++ /** @ogm_buff_len: length of the OGM packet buffer. rtnl protected */
+ int ogm_buff_len;
+
+ /** @ogm_seqno: OGM sequence number - used to identify each OGM */
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Thu, 3 Oct 2019 17:02:01 +0200
+Subject: batman-adv: Avoid free/alloc race when handling OGM buffer
+
+Each slave interface of an B.A.T.M.A.N. IV virtual interface has an OGM
+packet buffer which is initialized using data from the RTNL lock protected
+netdevice notifier and other rtnetlink related hooks. It is sent regularly
+via various slave interfaces of the batadv virtual interface and in this
+process also modified (realloced) to integrate additional state information
+via TVLV containers.
+
+It must be avoided that the worker item is executed without a common lock
+with the netdevice notifier/rtnetlink helpers. Otherwise it can either
+happen that half modified/freed data is sent out or functions modifying the
+OGM buffer try to access already freed memory regions.
+
+Reported-by: syzbot+0cc629f19ccb8534935b@syzkaller.appspotmail.com
+Fixes: ea6f8d42a595 ("batman-adv: move /proc interface handling to /sys")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/9b8ceef26c697d0c8319748428944c3339a498dc
+
+diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
+index 3db8a0278046c0a9f4d2604f0067ba4efe3ef588..cb27949f4086643ebd018a0a01ab0b848ce5123f 100644
+--- a/net/batman-adv/bat_iv_ogm.c
++++ b/net/batman-adv/bat_iv_ogm.c
+@@ -42,6 +42,7 @@
+ #include <linux/random.h>
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
++#include <linux/rtnetlink.h>
+ #include <linux/seq_file.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+@@ -379,6 +380,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+ unsigned char *ogm_buff;
+ u32 random_seqno;
+
++ ASSERT_RTNL();
++
+ /* randomize initial seqno to avoid collision */
+ get_random_bytes(&random_seqno, sizeof(random_seqno));
+ atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno);
+@@ -403,6 +406,8 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+
+ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface)
+ {
++ ASSERT_RTNL();
++
+ kfree(hard_iface->bat_iv.ogm_buff);
+ hard_iface->bat_iv.ogm_buff = NULL;
+ }
+@@ -412,6 +417,8 @@ 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;
+
++ ASSERT_RTNL();
++
+ batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+ ether_addr_copy(batadv_ogm_packet->orig,
+ hard_iface->net_dev->dev_addr);
+@@ -425,6 +432,8 @@ 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;
+
++ ASSERT_RTNL();
++
+ batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
+ batadv_ogm_packet->ttl = BATADV_TTL;
+ }
+@@ -935,6 +944,8 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+ u16 tvlv_len = 0;
+ unsigned long send_time;
+
++ ASSERT_RTNL();
++
+ if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
+ hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+ return;
+@@ -1791,16 +1802,12 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+ batadv_orig_node_put(orig_node);
+ }
+
+-static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
++static void
++batadv_iv_send_outstanding_forw_packet(struct batadv_forw_packet *forw_packet)
+ {
+- struct delayed_work *delayed_work;
+- struct batadv_forw_packet *forw_packet;
+ struct batadv_priv *bat_priv;
+ bool dropped = false;
+
+- delayed_work = to_delayed_work(work);
+- forw_packet = container_of(delayed_work, struct batadv_forw_packet,
+- delayed_work);
+ bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
+
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
+@@ -1829,6 +1836,20 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
+ batadv_forw_packet_free(forw_packet, dropped);
+ }
+
++static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
++{
++ struct delayed_work *delayed_work;
++ struct batadv_forw_packet *forw_packet;
++
++ delayed_work = to_delayed_work(work);
++ forw_packet = container_of(delayed_work, struct batadv_forw_packet,
++ delayed_work);
++
++ rtnl_lock();
++ batadv_iv_send_outstanding_forw_packet(forw_packet);
++ rtnl_unlock();
++}
++
+ static int batadv_iv_ogm_receive(struct sk_buff *skb,
+ struct batadv_hard_iface *if_incoming)
+ {
+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
+index 8eaec92aff8919f0c6ca6b05be22e592b7ae0e1a..d43f1ec4532d1fda1d50061e581f4770a6037739 100644
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -82,10 +82,10 @@ enum batadv_dhcp_recipient {
+ * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
+ */
+ struct batadv_hard_iface_bat_iv {
+- /** @ogm_buff: buffer holding the OGM packet */
++ /** @ogm_buff: buffer holding the OGM packet. rtnl protected */
+ unsigned char *ogm_buff;
+
+- /** @ogm_buff_len: length of the OGM packet buffer */
++ /** @ogm_buff_len: length of the OGM packet buffer. rtnl protected */
+ int ogm_buff_len;
+
+ /** @ogm_seqno: OGM sequence number - used to identify each OGM */
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Sun, 13 Oct 2019 21:03:06 +0200
+Subject: batman-adv: Introduce own OGM2 buffer mutex
+
+Only a single function is currently automatically locked by the rtnl_lock
+because (unlike B.A.T.M.A.N. IV) the OGM2 buffer is independent of the hard
+interfaces on which it will be transmitted. A private mutex can be used
+instead to avoid unnecessary delays which would have been introduced by the
+global lock.
+
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/8069c581f9097f1f9398f2d49047a1dab8093821
+
+diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
+index a9f949501ff3c354d38e3ad333901310391f27d8..bf9ea404abe7cbe1dd2113881856cd35b718b7d1 100644
+--- a/net/batman-adv/bat_v_ogm.c
++++ b/net/batman-adv/bat_v_ogm.c
+@@ -29,11 +29,12 @@
+ #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/random.h>
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+ #include <linux/stddef.h>
+@@ -142,7 +143,7 @@ static void batadv_v_ogm_send_softif(struct batadv_priv *bat_priv)
+ u16 tvlv_len = 0;
+ int ret;
+
+- ASSERT_RTNL();
++ lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex);
+
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
+ goto out;
+@@ -242,11 +243,12 @@ static void batadv_v_ogm_send(struct work_struct *work)
+ struct batadv_priv_bat_v *bat_v;
+ struct batadv_priv *bat_priv;
+
+- rtnl_lock();
+ 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);
+- rtnl_unlock();
++ mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex);
+ }
+
+ /**
+@@ -275,13 +277,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;
+
+- ASSERT_RTNL();
+-
++ 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);
+ }
+
+ /**
+@@ -885,8 +889,6 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv)
+ unsigned char *ogm_buff;
+ u32 random_seqno;
+
+- ASSERT_RTNL();
+-
+ bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN;
+ ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC);
+ if (!ogm_buff)
+@@ -905,6 +907,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;
+ }
+
+@@ -916,7 +920,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);
+ }
+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
+index d43f1ec4532d1fda1d50061e581f4770a6037739..05542a32f8c9c00b9d0cd7dbbab60cb773724613 100644
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -28,6 +28,7 @@
+ #include <linux/compiler.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 */
+@@ -1474,15 +1475,18 @@ struct batadv_softif_vlan {
+ * struct batadv_priv_bat_v - B.A.T.M.A.N. V per soft-interface private data
+ */
+ struct batadv_priv_bat_v {
+- /** @ogm_buff: buffer holding the OGM packet. rtnl protected */
++ /** @ogm_buff: buffer holding the OGM packet */
+ unsigned char *ogm_buff;
+
+- /** @ogm_buff_len: length of the OGM packet buffer. rtnl protected */
++ /** @ogm_buff_len: length of the OGM packet buffer */
+ int ogm_buff_len;
+
+ /** @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;
+ };
--- /dev/null
+From: Sven Eckelmann <sven@narfation.org>
+Date: Sun, 13 Oct 2019 21:03:07 +0200
+Subject: batman-adv: Avoid OGM workqueue synchronous cancel deadlock
+
+batadv_forw_packet_list_free can be called when an interface is being
+disabled. Under this circumstance, the rntl_lock will be held and while it
+calls cancel_delayed_work_sync.
+
+cancel_delayed_work_sync will stop the execution of the current context
+when the work item is currently processed. It can now happen that the
+cancel_delayed_work_sync was called when rtnl_lock was already called in
+batadv_iv_send_outstanding_bat_ogm_packet or when it was in the process of
+calling it. In this case, batadv_iv_send_outstanding_bat_ogm_packet waits
+for the lock and cancel_delayed_work_sync (which holds the rtnl_lock) is
+waiting for batadv_iv_send_outstanding_bat_ogm_packet to finish.
+
+This can only be avoided by not using (conflicting) blocking locks while
+cancel_delayed_work_sync is called. It also has the benefit that the
+ogm scheduling functionality can avoid unnecessary delays which can be
+introduced by a global lock.
+
+Fixes: 9b8ceef26c69 ("batman-adv: Avoid free/alloc race when handling OGM buffer")
+Signed-off-by: Sven Eckelmann <sven@narfation.org>
+
+Origin: upstream, https://git.open-mesh.org/batman-adv.git/commit/d3be478f1aa27b47f61c4a62e18eb063d47c9168
+
+diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
+index cb27949f4086643ebd018a0a01ab0b848ce5123f..b87bf2e511e0cd702a94594b8ddfe107ee17cef2 100644
+--- a/net/batman-adv/bat_iv_ogm.c
++++ b/net/batman-adv/bat_iv_ogm.c
+@@ -35,6 +35,7 @@
+ #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>
+@@ -42,7 +43,6 @@
+ #include <linux/random.h>
+ #include <linux/rculist.h>
+ #include <linux/rcupdate.h>
+-#include <linux/rtnetlink.h>
+ #include <linux/seq_file.h>
+ #include <linux/skbuff.h>
+ #include <linux/slab.h>
+@@ -380,7 +380,7 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+ unsigned char *ogm_buff;
+ u32 random_seqno;
+
+- ASSERT_RTNL();
++ mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
+ /* randomize initial seqno to avoid collision */
+ get_random_bytes(&random_seqno, sizeof(random_seqno));
+@@ -388,8 +388,10 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface)
+
+ 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;
+
+@@ -401,41 +403,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)
+ {
+- ASSERT_RTNL();
++ 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;
+
+- ASSERT_RTNL();
++ mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
+- batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
++ 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;
+
+- ASSERT_RTNL();
++ mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
+
+- batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff;
++ 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 */
+@@ -933,7 +953,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;
+@@ -944,11 +968,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+ u16 tvlv_len = 0;
+ unsigned long send_time;
+
+- ASSERT_RTNL();
+-
+- 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
+@@ -1016,6 +1036,17 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
+ 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_ogm_orig_update() - use OGM to update corresponding data in an
+ * originator
+@@ -1802,12 +1833,16 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
+ batadv_orig_node_put(orig_node);
+ }
+
+-static void
+-batadv_iv_send_outstanding_forw_packet(struct batadv_forw_packet *forw_packet)
++static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
+ {
++ struct delayed_work *delayed_work;
++ struct batadv_forw_packet *forw_packet;
+ struct batadv_priv *bat_priv;
+ bool dropped = false;
+
++ delayed_work = to_delayed_work(work);
++ forw_packet = container_of(delayed_work, struct batadv_forw_packet,
++ delayed_work);
+ bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
+
+ if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) {
+@@ -1836,20 +1871,6 @@ batadv_iv_send_outstanding_forw_packet(struct batadv_forw_packet *forw_packet)
+ batadv_forw_packet_free(forw_packet, dropped);
+ }
+
+-static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
+-{
+- struct delayed_work *delayed_work;
+- struct batadv_forw_packet *forw_packet;
+-
+- delayed_work = to_delayed_work(work);
+- forw_packet = container_of(delayed_work, struct batadv_forw_packet,
+- delayed_work);
+-
+- rtnl_lock();
+- batadv_iv_send_outstanding_forw_packet(forw_packet);
+- rtnl_unlock();
+-}
+-
+ static int batadv_iv_ogm_receive(struct sk_buff *skb,
+ struct batadv_hard_iface *if_incoming)
+ {
+diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
+index 2f0d42f2f913e74cf10c0c6ce89320434994cac5..48123e9e3a6d221a9033bc2949e19a306e973546 100644
+--- a/net/batman-adv/hard-interface.c
++++ b/net/batman-adv/hard-interface.c
+@@ -30,6 +30,7 @@
+ #include <linux/kernel.h>
+ #include <linux/kref.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);
+
+diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
+index 05542a32f8c9c00b9d0cd7dbbab60cb773724613..c843a69677d1e0eefaf6a1432541052b7cd2965a 100644
+--- a/net/batman-adv/types.h
++++ b/net/batman-adv/types.h
+@@ -83,14 +83,17 @@ enum batadv_dhcp_recipient {
+ * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data
+ */
+ struct batadv_hard_iface_bat_iv {
+- /** @ogm_buff: buffer holding the OGM packet. rtnl protected */
++ /** @ogm_buff: buffer holding the OGM packet */
+ unsigned char *ogm_buff;
+
+- /** @ogm_buff_len: length of the OGM packet buffer. rtnl protected */
++ /** @ogm_buff_len: length of the OGM packet buffer */
+ int ogm_buff_len;
+
+ /** @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;
+ };
+
+ /**