Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH net-next 17/17] net: sched: unlock rules update API
From: Vlad Buslov @ 2018-11-14 16:45 UTC (permalink / raw)
  To: Jiri Pirko
  Cc: David Miller, netdev@vger.kernel.org, jhs@mojatatu.com,
	xiyou.wangcong@gmail.com, ast@kernel.org, daniel@iogearbox.net
In-Reply-To: <20181114064453.GA2235@nanopsycho.orion>


On Wed 14 Nov 2018 at 06:44, Jiri Pirko <jiri@resnulli.us> wrote:
> Tue, Nov 13, 2018 at 02:46:54PM CET, vladbu@mellanox.com wrote:
>>On Mon 12 Nov 2018 at 17:30, David Miller <davem@davemloft.net> wrote:
>>> From: Vlad Buslov <vladbu@mellanox.com>
>>> Date: Mon, 12 Nov 2018 09:55:46 +0200
>>>
>>>> Register netlink protocol handlers for message types RTM_NEWTFILTER,
>>>> RTM_DELTFILTER, RTM_GETTFILTER as unlocked. Set rtnl_held variable that
>>>> tracks rtnl mutex state to be false by default.
>>>
>>> This whole conditional locking mechanism is really not clean and makes
>>> this code so much harder to understand and audit.
>>>
>>> Please improve the code so that this kind of construct is not needed.
>>>
>>> Thank you.
>>
>>Hi David,
>>
>>I considered several approaches to this problem and decided that this
>>one is most straightforward to implement. I understand your concern and
>>agree that this code is not easiest to understand and can suggest
>>several possible solutions that do not require this kind of elaborate
>>locking mechanism in cls API, but have their own drawbacks:
>>
>>1. Convert all qdiscs and classifiers to support unlocked execution,
>>like we did for actions. However, according to my experience with
>>converting flower classifier, these require much more code than actions.
>>I would estimate it to be more work than whole current unlocking effort
>>(hundred+ patches). Also, authors of some of them might be unhappy with
>>such intrusive changes. I don't think this approach is realistic.
>>
>>2. Somehow determine if rtnl is needed at the beginning of cls API rule
>>update functions. Currently, this is not possible because locking
>>requirements are determined by qdisc_class_ops and tcf_proto_ops 'flags'
>>field, which requires code to first do whole ops lookup sequence.
>>However, instead of class field I can put 'flags' in some kind of hash
>>table or array that will map qdisc/classifier type string to flags, so
>>it will be possible to determine locking requirements by just parsing
>>netlink message and obtaining flags by qdisc/classifier type. I do not
>>consider it pretty solution either, but maybe you have different
>>opinion.
>
> I think you will have to do 2. or some modification. Can't you just
> check for cls ability to run unlocked early on in tc_new_tfilter()?
> You would call tcf_proto_locking_check(nla_data(tca[TCA_KIND]), ...),
> which would do tcf_proto_lookup_ops() for ops and check the flags?

I guess that would work. However, such solution requires calling
tcf_proto_lookup_ops(), which iterates over tcf_proto_base list and
calls strcmp() for each proto, for every rule update call. That is why I
suggested to use some kind of optimized data structure for that purpose
in my first reply. Dunno if such solution will significantly impact rule
update performance. We don't have that many classifiers and their names
are short, so I guess not?

>
>
>>
>>3. Anything you can suggest? I might be missing something simple that
>>you would consider more elegant solution to this problem.
>>
>>Thanks,
>>Vlad
>>

^ permalink raw reply

* Re: [RFC PATCH 07/12] soc: qcom: ipa: IPA register abstraction
From: Alex Elder @ 2018-11-15  2:48 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: David Miller, Bjorn Andersson, Ilias Apalodimas, Networking, DTML,
	linux-arm-msm, linux-soc, Linux ARM, Linux Kernel Mailing List,
	syadagir, mjavid, Rob Herring, Mark Rutland
In-Reply-To: <CAK8P3a2FsgR=SYAWsgFURVni1ReiCugKs1iUAfQzZhPkbW8aOA@mail.gmail.com>

On 11/7/18 9:00 AM, Arnd Bergmann wrote:
> On Wed, Nov 7, 2018 at 1:33 AM Alex Elder <elder@linaro.org> wrote:
>> diff --git a/drivers/net/ipa/ipa_reg.c b/drivers/net/ipa/ipa_reg.c
>> new file mode 100644
>> index 000000000000..5e0aa6163235
>> --- /dev/null
>> +++ b/drivers/net/ipa/ipa_reg.c
>> @@ -0,0 +1,972 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +
>> +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
>> + * Copyright (C) 2018 Linaro Ltd.
>> + */
>> +
>> +#include <linux/types.h>
>> +#include <linux/io.h>
>> +#include <linux/bitfield.h>
>> +
>> +#include "ipa_reg.h"
>> +
>> +/* I/O remapped base address of IPA register space */
>> +static void __iomem *ipa_reg_virt;
> 
> This should of course be part of the device structure.

Yes, this should have been be in that structure to begin with.

I'm working through doing a comprehensive replacement of
global variables like this with values passed around as
arguments.  I've intended to do it all along but your nudge
pushed it to the top of my list.  It's a *lot* of work, much
more than I realized.  But I'm making rapid progress.

>> +/* struct ipa_reg_desc - descriptor for an abstracted hardware register
>> + *
>> + * @construct - fn to construct the register value from its field structure
>> + * @parse - function to parse register field values into its field structure
>> + * @offset - register offset relative to base address
>> + * @n_ofst - size multiplier for "N-parameterized" registers
>> + */
>> +struct ipa_reg_desc {
>> +       u32 (*construct)(enum ipa_reg reg, const void *fields);
>> +       void (*parse)(enum ipa_reg reg, void *fields, u32 val);
>> +       u32 offset;
>> +       u16 n_ofst;
>> +};
> 
> Indirect function pointers can be a bit expensive in the post-spectre
> days. It's probably not overly important if these are always part of
> an MMIO access function, but you should be careful about using
> these in the data path.

OK.

There used to be a more elaborate scheme for supporting
lots of versions, and I have tried to preserve at least part
of the underlying mechanism (the parse and construct functions).
Not all of these registers use the indirect functions, and
it looks to me like none of them are in the data path.

The most important registers for the fast path are found in
the GSI code.  And that doesn't use this construct--it only
reads and writes 32-bit registers.  (I think it differs
because it was originally developed by a different team.)

> How many different versions do we have to support in practice
I don't know for sure how many versions really were used,
but the original code had about 10 distinct version values,
many of which shared most (but not all) register definitions
(offset and bit field widths) with older versions.

With the upstream code the decision was made to ignore anything
older than IPA version 3 (and 3.5.1 in particular, which is
found in the SDM845 SoC).  

It may be that this parse/construct mechanism isn't justified
at this point.  I thought the way it presented a generic
interface was useful, but with just one (initial) hardware
target we don't (yet) realize its potential benefit.  It could
be added back later, as support for new versions is added.

As of now I don't plan to change this, but if you or someone
else feels it would be better without it I can do that.

					-Alex


>        Arnd
> 

^ permalink raw reply

* [PATCH net-next] isdn/hisax: remove set but not used variable 'total'
From: YueHaibing @ 2018-11-15  2:23 UTC (permalink / raw)
  To: davem, isdn; +Cc: linux-kernel, netdev, natechancellor, YueHaibing

Fixes gcc '-Wunused-but-set-variable' warning:

drivers/isdn/hisax/hfc_pci.c:277:6: warning:
 variable ‘total’ set but not used [-Wunused-but-set-variable]

It never used since git history start.

Signed-off-by: YueHaibing <yuehaibing@huawei.com>
---
 drivers/isdn/hisax/hfc_pci.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index ea0e4c6..5b719b5 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -274,7 +274,7 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type *bz, u_char *bdata, int count
 	u_char *ptr, *ptr1, new_f2;
 	struct sk_buff *skb;
 	struct IsdnCardState *cs = bcs->cs;
-	int total, maxlen, new_z2;
+	int maxlen, new_z2;
 	z_type *zp;
 
 	if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
@@ -297,7 +297,6 @@ hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type *bz, u_char *bdata, int count
 	} else if (!(skb = dev_alloc_skb(count - 3)))
 		printk(KERN_WARNING "HFCPCI: receive out of memory\n");
 	else {
-		total = count;
 		count -= 3;
 		ptr = skb_put(skb, count);
 
-- 
2.7.0

^ permalink raw reply related

* Re: [RFC v1 1/3] udp_tunnel: add config option to bind to a device
From: Nicolas Dichtel @ 2018-11-14 16:07 UTC (permalink / raw)
  To: Alexis Bauvin, dsa, roopa; +Cc: netdev, akherbouche
In-Reply-To: <20181114093104.93286-2-abauvin@scaleway.com>

Le 14/11/2018 à 10:31, Alexis Bauvin a écrit :
> UDP tunnel sockets are always opened unbound to a specific device. This
> patch allow the socket to be bound on a custom device, which
> incidentally makes UDP tunnels VRF-aware if binding to an l3mdev.
> 
> Signed-off-by: Alexis Bauvin <abauvin@scaleway.com>
> Reviewed-by: Amine Kherbouche <akherbouche@scaleway.com>
> Tested-by: Amine Kherbouche <akherbouche@scaleway.com>
What is the difference with the previous version?
Maybe a cover letter would help to track the history.


Regards,
Nicolas

^ permalink raw reply

* [PATCH V3 6/7] net: maclorawan: Implement maclorawan class module
From: Jian-Hong Pan @ 2018-11-14 16:01 UTC (permalink / raw)
  To: Andreas Färber, David S . Miller
  Cc: netdev, linux-arm-kernel, linux-kernel, Marcel Holtmann,
	Dollar Chen, Ken Yu, linux-wpan, Stefan Schmidt, Jian-Hong Pan
In-Reply-To: <20181105.101610.1437737564548154497.davem@davemloft.net>

LoRaWAN defined by LoRa Alliance(TM) is the MAC layer over LoRa devices.

This patch implements part of Class A end-devices SoftMAC defined in
LoRaWAN(TM) Specification Ver. 1.0.2:
1. End-device receive slot timing
2. Only single channel and single data rate for now
3. Unconfirmed data up/down message types

On the other side, it defines the basic interface and operation
functions for compatible LoRa device drivers.

Signed-off-by: Jian-Hong Pan <starnight@g.ncu.edu.tw>
---
V2:
- Split the LoRaWAN class module patch in V1 into LoRaWAN socket and
  LoRaWAN Soft MAC modules
- Modify for Big/Little-Endian
- Use SPDX license identifiers

V3:
- Remove the decoration word - inline of the functions
- Order local variables from longest to shortest line in the functions
- Change the calling mac_cb function to lrw_get_mac_cb macro

 net/maclorawan/Kconfig  |  14 +
 net/maclorawan/Makefile |   2 +
 net/maclorawan/mac.c    | 520 ++++++++++++++++++++++++++++++++++
 net/maclorawan/main.c   | 605 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1141 insertions(+)
 create mode 100644 net/maclorawan/Kconfig
 create mode 100644 net/maclorawan/Makefile
 create mode 100644 net/maclorawan/mac.c
 create mode 100644 net/maclorawan/main.c

diff --git a/net/maclorawan/Kconfig b/net/maclorawan/Kconfig
new file mode 100644
index 000000000000..177537d5f59f
--- /dev/null
+++ b/net/maclorawan/Kconfig
@@ -0,0 +1,14 @@
+config MACLORAWAN
+	tristate "Generic LoRaWAN Soft Networking Stack (maclorawan)"
+	depends on LORAWAN
+	select CRYPTO
+	select CRYPTO_CMAC
+	select CRYPTO_CBC
+	select CRYPTO_AES
+	---help---
+	  This option enables the hardware independent LoRaWAN
+	  networking stack for SoftMAC devices (the ones implementing
+	  only PHY level of LoRa standard).
+
+	  If you plan to use HardMAC LoRaWAN devices, you can say N
+	  here.  Alternatively you can say M to compile it as a module.
diff --git a/net/maclorawan/Makefile b/net/maclorawan/Makefile
new file mode 100644
index 000000000000..562831e66c82
--- /dev/null
+++ b/net/maclorawan/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MACLORAWAN)	+= maclorawan.o
+maclorawan-objs			:= main.o mac.o crypto.o
diff --git a/net/maclorawan/mac.c b/net/maclorawan/mac.c
new file mode 100644
index 000000000000..2d9f322c364e
--- /dev/null
+++ b/net/maclorawan/mac.c
@@ -0,0 +1,520 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */
+/*-
+ * LoRaWAN soft MAC
+ *
+ * Copyright (c) 2018 Jian-Hong, Pan <starnight@g.ncu.edu.tw>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/lora/lorawan.h>
+#include <linux/lora/lorawan_netdev.h>
+
+#include "maclorawan.h"
+#include "crypto.h"
+
+static void rx_timeout_work(struct work_struct *work);
+
+struct lrw_session *
+lrw_alloc_ss(struct lrw_struct *lrw_st)
+{
+	struct lrw_session *ss;
+
+	ss = kzalloc(sizeof(struct lrw_session), GFP_KERNEL);
+	if (!ss)
+		goto lrw_alloc_ss_end;
+
+	ss->lrw_st = lrw_st;
+	ss->devaddr = lrw_st->devaddr;
+	INIT_LIST_HEAD(&ss->entry);
+
+	ss->tx_should_ack = false;
+	ss->retry = 3;
+	spin_lock_init(&ss->state_lock);
+	INIT_WORK(&ss->timeout_work, rx_timeout_work);
+
+lrw_alloc_ss_end:
+	return ss;
+}
+
+void
+lrw_free_ss(struct lrw_session *ss)
+{
+	netdev_dbg(ss->lrw_st->ndev, "%s\n", __func__);
+	if (ss->tx_skb)
+		consume_skb(ss->tx_skb);
+	netdev_dbg(ss->lrw_st->ndev, "%s: free rx skb\n", __func__);
+	if (ss->rx_skb)
+		consume_skb(ss->rx_skb);
+
+	netdev_dbg(ss->lrw_st->ndev, "%s: free ss\n", __func__);
+	kfree(ss);
+}
+
+void
+lrw_del_ss(struct lrw_session *ss)
+{
+	netdev_dbg(ss->lrw_st->ndev, "%s\n", __func__);
+	list_del(&ss->entry);
+	lrw_free_ss(ss);
+}
+
+void
+lrw_del_all_ss(struct lrw_struct *lrw_st)
+{
+	struct lrw_session *ss, *tmp;
+
+	mutex_lock(&lrw_st->ss_list_lock);
+	lrw_st->_cur_ss = NULL;
+	list_for_each_entry_safe(ss, tmp, &lrw_st->ss_list, entry) {
+		del_timer(&ss->timer);
+		lrw_del_ss(ss);
+	}
+	mutex_unlock(&lrw_st->ss_list_lock);
+}
+
+void
+lrw_ready_hw(struct lrw_struct *lrw_st)
+{
+	lrw_st->state = LRW_STATE_IDLE;
+}
+
+int
+lrw_start_hw(struct lrw_struct *lrw_st)
+{
+	int ret = 0;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+	lrw_st->nwks_shash_tfm = lrw_mic_key_setup(lrw_st->nwkskey,
+						   LRW_KEY_LEN);
+	lrw_st->nwks_skc_tfm = lrw_encrypt_key_setup(lrw_st->nwkskey,
+						     LRW_KEY_LEN);
+	lrw_st->apps_skc_tfm = lrw_encrypt_key_setup(lrw_st->appskey,
+						     LRW_KEY_LEN);
+	lrw_st->state = LRW_START;
+	ret = lrw_st->ops->start(&lrw_st->hw);
+	if (!ret)
+		lrw_ready_hw(lrw_st);
+
+	return ret;
+}
+
+void
+lrw_stop_hw(struct lrw_struct *lrw_st)
+{
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+	lrw_st->state = LRW_STOP;
+	netdev_dbg(lrw_st->ndev, "%s: going to stop hardware\n", __func__);
+	lrw_st->ops->stop(&lrw_st->hw);
+
+	netdev_dbg(lrw_st->ndev, "%s: going to kill tasks & flush works", __func__);
+	tasklet_kill(&lrw_st->xmit_task);
+	flush_work(&lrw_st->rx_work);
+
+	netdev_dbg(lrw_st->ndev, "%s: going to delete all session\n", __func__);
+	lrw_del_all_ss(lrw_st);
+
+	netdev_dbg(lrw_st->ndev, "%s: going to free mic tfm\n", __func__);
+	lrw_mic_key_free(lrw_st->nwks_shash_tfm);
+	netdev_dbg(lrw_st->ndev, "%s: going to free nwks tfm\n", __func__);
+	lrw_encrypt_key_free(lrw_st->nwks_skc_tfm);
+	netdev_dbg(lrw_st->ndev, "%s: going to free apps tfm\n", __func__);
+	lrw_encrypt_key_free(lrw_st->apps_skc_tfm);
+}
+
+void
+lrw_prepare_tx_frame(struct lrw_session *ss)
+{
+	struct lrw_struct *lrw_st = ss->lrw_st;
+	struct sk_buff *skb = ss->tx_skb;
+	u8 mhdr, fctrl, fport, mic[4];
+	__le32 le_devaddr;
+	__le16 le_fcnt_up;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	/* Encrypt the plain buffer content */
+	lrw_encrypt_buf(lrw_st->apps_skc_tfm, LRW_UPLINK,
+			ss->devaddr, ss->fcnt_up, skb->data, skb->len);
+
+	/* Push FPort */
+	if (skb->len) {
+		fport = ss->fport;
+		memcpy(skb_push(skb, LRW_FPORT_LEN), &fport, LRW_FPORT_LEN);
+	}
+
+	/* Push FCnt_Up */
+	le_fcnt_up = cpu_to_le16(ss->fcnt_up);
+	memcpy(skb_push(skb, 2), &le_fcnt_up, 2);
+
+	/* Push FCtrl */
+	fctrl = 0;
+	if (lrw_st->rx_should_ack) {
+		fctrl |= 0x20;
+		lrw_st->rx_should_ack = false;
+	}
+	memcpy(skb_push(skb, 1), &fctrl, 1);
+
+	/* Push DevAddr */
+	le_devaddr = cpu_to_le32(ss->devaddr);
+	memcpy(skb_push(skb, LRW_DEVADDR_LEN), &le_devaddr, LRW_DEVADDR_LEN);
+
+	/* Push MHDR */
+	mhdr = LRW_UNCONFIRMED_DATA_UP << 5;
+	if ((mhdr & (0x6 << 5)) == (0x4 << 5))
+		ss->tx_should_ack = true;
+	memcpy(skb_push(skb, LRW_MHDR_LEN), &mhdr, LRW_MHDR_LEN);
+
+	/* Put MIC */
+	lrw_calc_mic(lrw_st->nwks_shash_tfm, LRW_UPLINK,
+		     ss->devaddr, ss->fcnt_up, skb->data, skb->len, mic);
+	memcpy(skb_put(skb, LRW_MIC_LEN), mic, LRW_MIC_LEN);
+}
+
+void
+lrw_xmit(unsigned long data)
+{
+	struct lrw_struct *lrw_st = (struct lrw_struct *) data;
+	struct lrw_session *ss = lrw_st->_cur_ss;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+	ss->state = LRW_XMITTING_SS;
+	lrw_st->ops->xmit_async(&lrw_st->hw, ss->tx_skb);
+}
+
+void
+lrw_parse_frame(struct lrw_session *ss, struct sk_buff *skb)
+{
+	struct lrw_fhdr *fhdr = &ss->rx_fhdr;
+	__le16 *p_fcnt;
+
+	pr_debug("%s: %s\n", LORAWAN_MODULE_NAME, __func__);
+
+	/* Get message type */
+	fhdr->mtype = skb->data[0];
+	skb_pull(skb, LRW_MHDR_LEN);
+
+	/* Trim Device Address */
+	skb_pull(skb, 4);
+
+	/* Get frame control */
+	fhdr->fctrl = skb->data[0];
+	skb_pull(skb, 1);
+
+	/* Ack the original TX frame if it should be acked */
+	if (ss->tx_should_ack && (fhdr->fctrl & 0x20))
+		ss->tx_should_ack = false;
+
+	/* Get frame count */
+	p_fcnt = (__le16 *)skb->data;
+	fhdr->fcnt = le16_to_cpu(*p_fcnt);
+	skb_pull(skb, 2);
+
+	/* Get frame options */
+	fhdr->fopts_len = fhdr->fctrl & 0xF;
+	if (fhdr->fopts_len > 0) {
+		memcpy(fhdr->fopts, skb->data, fhdr->fopts_len);
+		skb_pull(skb, fhdr->fopts_len);
+	}
+
+	/* TODO: Parse frame options */
+
+	/* Remove message integrity code */
+	skb_trim(skb, skb->len - LRW_MIC_LEN);
+}
+
+struct lrw_session *
+lrw_rx_skb_2_session(struct lrw_struct *lrw_st, struct sk_buff *rx_skb)
+{
+	struct lrw_session *ss;
+	__le16 *p_fcnt;
+	u16 fcnt;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	p_fcnt = (__le16 *)(rx_skb->data + 6);
+	fcnt = le16_to_cpu(*p_fcnt);
+
+	/* Find the corresponding session */
+	ss = lrw_st->_cur_ss;
+
+	/* Frame count downlink check */
+	if (fcnt >= (ss->fcnt_down & 0xFFFF))
+		ss->rx_skb = rx_skb;
+	else
+		ss = NULL;
+
+	return ss;
+}
+
+void
+lrw_rx_work(struct work_struct *work)
+{
+	struct lrw_struct *lrw_st;
+	struct lrw_session *ss;
+	struct sk_buff *skb;
+
+	lrw_st = container_of(work, struct lrw_struct, rx_work);
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	skb = lrw_st->rx_skb_list.next;
+	skb_dequeue(&lrw_st->rx_skb_list);
+
+	/* Check and parse the RX frame */
+	ss = lrw_rx_skb_2_session(lrw_st, skb);
+	if (!ss)
+		goto lrw_rx_work_not_new_frame;
+
+	lrw_parse_frame(ss, skb);
+
+	/* Check the TX frame is acked or not */
+	if (ss->tx_should_ack) {
+		ss->rx_skb = NULL;
+		goto lrw_rx_work_not_new_frame;
+	}
+
+	/* The TX frame is acked or no need to be acked */
+	del_timer(&ss->timer);
+	lrw_st->rx_should_ack = (ss->rx_fhdr.mtype & 0xC0) == 0x40;
+
+	lrw_st->ndev->stats.rx_packets++;
+	lrw_st->ndev->stats.rx_bytes += ss->rx_skb->len;
+
+	if (ss->rx_skb->len > 0) {
+		spin_lock_bh(&ss->state_lock);
+		ss->state = LRW_RXRECEIVED_SS;
+		spin_unlock_bh(&ss->state_lock);
+
+		lrw_get_mac_cb(skb)->devaddr = lrw_st->devaddr;
+		netif_receive_skb(skb);
+
+		ss->rx_skb = NULL;
+	}
+
+	mutex_lock(&lrw_st->ss_list_lock);
+	lrw_st->fcnt_down = ss->rx_fhdr.fcnt;
+	lrw_st->_cur_ss = NULL;
+	lrw_del_ss(ss);
+	lrw_st->state = LRW_STATE_IDLE;
+	mutex_unlock(&lrw_st->ss_list_lock);
+
+	return;
+
+lrw_rx_work_not_new_frame:
+	/* Drop the RX frame if checked failed */
+	kfree_skb(skb);
+}
+
+int
+lrw_check_mic(struct crypto_shash *tfm, struct sk_buff *skb)
+{
+	u32 devaddr;
+	size_t len;
+	u8 cks[4];
+	u16 fcnt;
+	u8 *buf;
+	u8 *mic;
+
+	buf = skb->data;
+	devaddr = le32_to_cpu(*((__le32 *)(buf + LRW_MHDR_LEN)));
+	fcnt = le16_to_cpu(*(__le16 *)(buf + 6));
+	len = skb->len - 4;
+	mic = skb->data + len;
+
+	lrw_calc_mic(tfm, LRW_DOWNLINK, devaddr, fcnt, buf, len, cks);
+
+	return (!memcmp(cks, mic, 4));
+}
+
+/**
+ * lrw_rx_irqsave - Tell LoRaWAN module that there is new received frame
+ * @hw:		the LoRa device
+ * @skb:	the new received frame
+ */
+void
+lrw_rx_irqsave(struct lrw_hw *hw, struct sk_buff *skb)
+{
+	struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw);
+	u32 devaddr;
+	u8 mtype;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	mtype = skb->data[0] >> 5;
+	devaddr = le32_to_cpu(*(__le32 *)(skb->data + LRW_MHDR_LEN));
+
+	/* Check the frame is the downlink frame */
+	if (((mtype == LRW_UNCONFIRMED_DATA_DOWN)
+	      || (mtype == LRW_CONFIRMED_DATA_DOWN))
+	    && (devaddr == lrw_st->devaddr)
+	    && lrw_check_mic(lrw_st->nwks_shash_tfm, skb)) {
+		skb_queue_tail(&lrw_st->rx_skb_list, skb);
+		schedule_work(&lrw_st->rx_work);
+	}
+	else {
+		kfree_skb(skb);
+	}
+}
+EXPORT_SYMBOL(lrw_rx_irqsave);
+
+static void
+lrw_rexmit(struct timer_list *timer)
+{
+	struct lrw_session *ss = container_of(timer, struct lrw_session, timer);
+	struct lrw_struct *lrw_st = ss->lrw_st;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	lrw_st->state = LRW_STATE_TX;
+	lrw_xmit((unsigned long) lrw_st);
+}
+
+static void
+rx_timeout_work(struct work_struct *work)
+{
+	struct lrw_struct *lrw_st;
+	struct lrw_session *ss;
+
+	ss = container_of(work, struct lrw_session, timeout_work);
+	lrw_st = ss->lrw_st;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+	mutex_lock(&lrw_st->ss_list_lock);
+	lrw_st->_cur_ss = NULL;
+	lrw_st->state = LRW_STATE_IDLE;
+	lrw_del_ss(ss);
+	mutex_unlock(&lrw_st->ss_list_lock);
+}
+
+static void
+rx2_timeout_isr(struct timer_list *timer)
+{
+	struct lrw_session *ss = container_of(timer, struct lrw_session, timer);
+	struct lrw_struct *lrw_st = ss->lrw_st;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	/* Check TX is acked or not */
+	if (!ss->tx_should_ack) {
+		spin_lock_bh(&ss->state_lock);
+		if (ss->state != LRW_RXRECEIVED_SS)
+			ss->state = LRW_RXTIMEOUT_SS;
+		spin_unlock_bh(&ss->state_lock);
+
+		if (ss->state == LRW_RXTIMEOUT_SS) {
+			netdev_dbg(lrw_st->ndev, "%s: rx time out\n", __func__);
+			goto rx2_timeout_isr_no_retry_rx_frame;
+		}
+		else {
+			return;
+		}
+	}
+
+	/* Check the session need to be retransmitted or not */
+	if (ss->retry > 0) {
+		ss->state = LRW_RETRANSMIT_SS;
+		ss->retry--;
+
+		/* Start timer for ack timeout and retransmit */
+		ss->timer.function = lrw_rexmit;
+		ss->timer.expires = jiffies_64 + ss->ack_timeout * HZ;
+		add_timer(&ss->timer);
+	}
+	else {
+		/* Retry failed */
+rx2_timeout_isr_no_retry_rx_frame:
+		schedule_work(&ss->timeout_work);
+	}
+}
+
+static void
+rx2_delay_isr(struct timer_list *timer)
+{
+	struct lrw_session *ss = container_of(timer, struct lrw_session, timer);
+	struct lrw_struct *lrw_st = ss->lrw_st;
+	unsigned long delay;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	/* Start timer for RX2 window */
+	ss->timer.function = rx2_timeout_isr;
+	delay = jiffies_64 + (ss->rx2_window + 20) * HZ / 1000 + HZ;
+	ss->timer.expires = delay;
+	add_timer(&ss->timer);
+
+	/* Start LoRa hardware to RX2 window */
+	ss->state = LRW_RX2_SS;
+	lrw_st->ops->start_rx_window(&lrw_st->hw, ss->rx2_window + 20);
+}
+
+static void
+rx1_delay_isr(struct timer_list *timer)
+{
+	struct lrw_session *ss = container_of(timer, struct lrw_session, timer);
+	struct lrw_struct *lrw_st = ss->lrw_st;
+	unsigned long delay;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	/* Start timer for RX_Delay2 - RX_Delay2 */
+	ss->timer.function = rx2_delay_isr;
+	delay = jiffies_64 + (ss->rx_delay2 - ss->rx_delay1) * HZ - 20 * HZ / 1000;
+	ss->timer.expires = delay;
+	add_timer(&ss->timer);
+
+	/* Start LoRa hardware to RX1 window */
+	ss->state = LRW_RX1_SS;
+	lrw_st->ops->start_rx_window(&lrw_st->hw, ss->rx1_window + 20);
+}
+
+void
+lrw_sent_tx_work(struct lrw_struct *lrw_st, struct sk_buff *skb)
+{
+	struct lrw_session *ss = lrw_st->_cur_ss;
+	struct net_device *ndev;
+	unsigned long delay;
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	ss->state = LRW_XMITTED;
+
+	/* Start session timer for RX_Delay1 */
+	timer_setup(&ss->timer, rx1_delay_isr, 0);
+	delay = jiffies_64 + ss->rx_delay1 * HZ - 20 * HZ / 1000;
+	ss->timer.expires = delay;
+	add_timer(&ss->timer);
+
+	ndev = skb->dev;
+	ndev->stats.tx_packets++;
+	ndev->stats.tx_bytes += skb->len;
+	dev_consume_skb_any(skb);
+	ss->tx_skb = NULL;
+}
+
+/**
+ * lrw_xmit_complete - Tell LoRaWAN module that the frame is xmitted completely
+ * @hw:		the LoRa device
+ * @skb:	the xmitted frame
+ */
+void
+lrw_xmit_complete(struct lrw_hw *hw, struct sk_buff *skb)
+{
+	struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw);
+
+	netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+	lrw_sent_tx_work(lrw_st, skb);
+	lrw_st->state = LRW_STATE_RX;
+}
+EXPORT_SYMBOL(lrw_xmit_complete);
diff --git a/net/maclorawan/main.c b/net/maclorawan/main.c
new file mode 100644
index 000000000000..9ca778706880
--- /dev/null
+++ b/net/maclorawan/main.c
@@ -0,0 +1,605 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */
+/*-
+ * LoRaWAN soft MAC
+ *
+ * Copyright (c) 2018 Jian-Hong, Pan <starnight@g.ncu.edu.tw>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+
+#include <linux/lora/lorawan.h>
+#include <linux/lora/lorawan_netdev.h>
+#include "maclorawan.h"
+
+#define	PHY_NAME		"lora"
+
+/* Need to find a way to define or assign */
+#define	LORAWAN_MTU		20
+
+static struct class *lrw_sys_class;
+
+static void
+lrw_if_setup(struct net_device *ndev)
+{
+	ndev->addr_len = LRW_DEVADDR_LEN;
+	memset(ndev->broadcast, 0xFF, ndev->addr_len);
+	ndev->type = ARPHRD_LORAWAN;
+
+	ndev->hard_header_len = LRW_MHDR_LEN + LRW_FHDR_MAX_LEN + LRW_FPORT_LEN;
+	ndev->needed_tailroom = LRW_MIC_LEN;
+
+	/**
+	 * TODO: M should be a dynamic value defined by Regional Parameters,
+	 * 	 Being fixed for now.  Going to be changed.
+	 */
+	ndev->mtu = LORAWAN_MTU;
+}
+
+/**
+ * lrw_alloc_hw - Allocate a memory space for the LoRa device
+ * @priv_data_len:	the private data size
+ * @lrw_operations:	the implemented operations of the LoRa device
+ *
+ * Return:		address of the LoRa device or NULL for failed
+ */
+struct lrw_hw *
+lrw_alloc_hw(size_t priv_data_len, struct lrw_operations *ops)
+{
+	struct lrw_struct *lrw_st;
+	struct net_device *ndev;
+	int ret;
+
+	if (WARN_ON(!ops || !ops->start || !ops->stop || !ops->xmit_async ||
+		    !ops->set_txpower || !ops->set_dr ||
+		    !ops->start_rx_window || !ops->set_state))
+		return NULL;
+
+	/* In memory it'll be like this:
+	 *
+	 * +-----------------------+
+	 * | struct net_device     |
+	 * +-----------------------+
+	 * | struct lrw_struct     |
+	 * +-----------------------+
+	 * | driver's private data |
+	 * +-----------------------+
+	 */
+	ndev = alloc_netdev(sizeof(struct lrw_struct) + priv_data_len,
+			    PHY_NAME"%d", NET_NAME_ENUM, lrw_if_setup);
+	if (!ndev)
+		return ERR_PTR(-ENOMEM);
+	ret = dev_alloc_name(ndev, ndev->name);
+	if (ret < 0)
+		goto lrw_alloc_hw_err;
+
+	lrw_st = (struct lrw_struct *)netdev_priv(ndev);
+	lrw_st->ndev = ndev;
+
+	lrw_st->state = LRW_STOP;
+	lrw_st->ops = ops;
+	lrw_st->hw.priv = (void *) lrw_st + sizeof(struct lrw_struct);
+
+	ndev->flags |= IFF_NOARP;
+	ndev->features |= NETIF_F_HW_CSUM;
+
+	return &lrw_st->hw;
+
+lrw_alloc_hw_err:
+	free_netdev(ndev);
+	return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(lrw_alloc_hw);
+
+/**
+ * lrw_free_hw - Free the LoRa device's memory resource
+ * @hw:		the LoRa device going to be freed
+ */
+void
+lrw_free_hw(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	free_netdev(lrw_st->ndev);
+}
+EXPORT_SYMBOL(lrw_free_hw);
+
+/**
+ * lrw_set_deveui - Set the LoRa device's DevEUI
+ * @hw:		the LoRa device going to be set
+ * @eui:	the global end-device ID in IEEE EUI64 address space
+ */
+void
+lrw_set_deveui(struct lrw_hw *hw, u64 eui)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	lrw_st->dev_eui = eui;
+}
+EXPORT_SYMBOL(lrw_set_deveui);
+
+/**
+ * lrw_get_deveui - Get the LoRa device's DevEUI
+ * @hw:		the LoRa device going to be got from
+ *
+ * Return:	the device's DevEUI in IEEE EUI64 address space
+ */
+u64
+lrw_get_deveui(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	return lrw_st->dev_eui;
+}
+EXPORT_SYMBOL(lrw_get_deveui);
+
+/**
+ * lrw_set_appeui - Set the LoRa device's AppEUI
+ * @hw:		the LoRa device going to be set
+ * @eui:	the global end-device ID in IEEE EUI64 address space
+ */
+void
+lrw_set_appeui(struct lrw_hw *hw, u64 eui)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	lrw_st->app_eui = eui;
+}
+EXPORT_SYMBOL(lrw_set_appeui);
+
+/**
+ * lrw_get_appeui - Get the LoRa device's AppEUI
+ * @hw:		the LoRa device going to be got from
+ *
+ * Return:	the device's AppEUI in IEEE EUI64 address space
+ */
+u64
+lrw_get_appeui(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	return lrw_st->app_eui;
+}
+EXPORT_SYMBOL(lrw_get_appeui);
+
+/**
+ * lrw_set_devaddr - Set the LoRa device's address
+ * @hw:		the LoRa device going to be set
+ * @devaddr:	the device address
+ */
+void
+lrw_set_devaddr(struct lrw_hw *hw, u32 devaddr)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	lrw_st->devaddr = devaddr;
+}
+EXPORT_SYMBOL(lrw_set_devaddr);
+
+/**
+ * lrw_get_devaddr - Get the LoRa device's address
+ * @hw:		the LoRa device going to be got from
+ *
+ * Return:	the device address
+ */
+u32
+lrw_get_devaddr(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+	return lrw_st->devaddr;
+}
+EXPORT_SYMBOL(lrw_get_devaddr);
+
+/**
+ * lrw_add_hw - Add a LoRaWAN hardware as a network device
+ * @lrw_st:	the LoRa device going to be added
+ *
+ * Return:	0 / other number for success / failed
+ */
+static int
+lrw_add_hw(struct lrw_struct *lrw_st)
+{
+	struct net_device *ndev = lrw_st->ndev;
+	__be32 be_addr;
+	int ret;
+
+	lrw_st->fcnt_up = 0;
+	lrw_st->fcnt_down = 0;
+	lrw_st->_cur_ss = NULL;
+
+	mutex_init(&lrw_st->ss_list_lock);
+	INIT_LIST_HEAD(&lrw_st->ss_list);
+
+	tasklet_init(&lrw_st->xmit_task, lrw_xmit, (unsigned long) lrw_st);
+	INIT_WORK(&lrw_st->rx_work, lrw_rx_work);
+
+	be_addr = cpu_to_be32(lrw_st->devaddr);
+	memcpy(ndev->perm_addr, &be_addr, ndev->addr_len);
+	memcpy(ndev->dev_addr, ndev->perm_addr, ndev->addr_len);
+
+	write_pnet(&lrw_st->_net, &init_net);
+	ret = register_netdev(ndev);
+
+	return ret;
+}
+
+/**
+ * lrw_remove_hw - Remove a LoRaWAN hardware from a network device
+ * @lrw_st:	the LoRa device going to be removed
+ */
+static void
+lrw_remove_hw(struct lrw_struct *lrw_st)
+{
+	unregister_netdev(lrw_st->ndev);
+	tasklet_kill(&lrw_st->xmit_task);
+}
+
+bool
+ready2write(struct lrw_struct *lrw_st)
+{
+	bool status = false;
+
+	if ((!lrw_st->_cur_ss) && (lrw_st->state == LRW_STATE_IDLE))
+		status = true;
+
+	return status;
+}
+
+bool
+ready2read(struct lrw_struct *lrw_st)
+{
+	struct lrw_session *ss;
+	bool status = false;
+
+	if (!list_empty(&lrw_st->ss_list) && (lrw_st->state != LRW_STOP)) {
+		ss = list_first_entry(&lrw_st->ss_list,
+				      struct lrw_session,
+				      entry);
+		if (ss->state == LRW_RXRECEIVED_SS)
+			status = true;
+	}
+
+	return status;
+}
+
+static int
+lrw_if_up(struct net_device *ndev)
+{
+	struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev);
+	int ret = -EBUSY;
+
+	if (lrw_st->state == LRW_STOP) {
+		ret = lrw_start_hw(lrw_st);
+		netif_start_queue(ndev);
+	}
+
+	return ret;
+}
+
+static int
+lrw_if_down(struct net_device *ndev)
+{
+	struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev);
+
+	if (lrw_st->state != LRW_STOP) {
+		netif_stop_queue(ndev);
+		lrw_stop_hw(lrw_st);
+	}
+
+	return 0;
+}
+
+static netdev_tx_t
+lrw_if_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev);
+	struct lrw_session *ss;
+	netdev_tx_t ret;
+
+	ret = NETDEV_TX_OK;
+
+	ss = lrw_alloc_ss(lrw_st);
+	if (!ss)
+		return NETDEV_TX_BUSY;
+
+	mutex_lock(&lrw_st->ss_list_lock);
+	if (ready2write(lrw_st)) {
+		list_add_tail(&ss->entry, &lrw_st->ss_list);
+		lrw_st->state = LRW_STATE_TX;
+		lrw_st->_cur_ss = ss;
+		ss->fcnt_up = lrw_st->fcnt_up;
+		ss->fcnt_down = lrw_st->fcnt_down;
+		/* TODO: RX delay #1/#2 should be set by regional parameters */
+		ss->rx_delay1 = 1;
+		ss->rx_delay2 = 2;
+		ss->rx1_window = 500;
+		ss->rx2_window = 500;
+	}
+	else
+		ret = NETDEV_TX_BUSY;
+	mutex_unlock(&lrw_st->ss_list_lock);
+
+	if (ret == NETDEV_TX_OK) {
+		ss->state = LRW_INIT_SS;
+		ss->tx_skb = skb;
+		lrw_prepare_tx_frame(ss);
+		tasklet_schedule(&lrw_st->xmit_task);
+	}
+	else
+		lrw_free_ss(ss);
+
+	return ret;
+}
+
+static int
+lrw_if_get_addr(struct lrw_struct *lrw_st, struct sockaddr_lorawan *addr)
+{
+	int ret = 0;
+
+	switch (addr->addr_in.addr_type) {
+	case LRW_ADDR_DEVADDR:
+		addr->addr_in.devaddr = lrw_st->devaddr;
+		break;
+	case LRW_ADDR_DEVEUI:
+		addr->addr_in.dev_eui = lrw_st->dev_eui;
+		break;
+	case LRW_ADDR_APPEUI:
+		addr->addr_in.app_eui = lrw_st->app_eui;
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+
+static int
+lrw_if_set_addr(struct lrw_struct *lrw_st, struct sockaddr_lorawan *addr)
+{
+	struct lrw_hw *hw = &lrw_st->hw;
+	int ret = 0;
+
+	if (netif_running(lrw_st->ndev))
+		return -EBUSY;
+
+	switch (addr->addr_in.addr_type) {
+	case LRW_ADDR_DEVADDR:
+		lrw_set_devaddr(hw, addr->addr_in.devaddr);
+		break;
+	case LRW_ADDR_DEVEUI:
+		lrw_set_deveui(hw, addr->addr_in.dev_eui);
+		break;
+	case LRW_ADDR_APPEUI:
+		lrw_set_appeui(hw, addr->addr_in.app_eui);
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+
+static void
+swap_bytes(u8 *dst, u8 *src, size_t l)
+{
+	/* Human reading is big-endian, but LoRaWAN is little-endian */
+	unsigned int i;
+	for (i = 0; i < l; i++)
+		dst[i] = src[l - i - 1];
+}
+
+int
+lrw_set_key(struct lrw_hw *hw, u8 type, u8 *key, size_t key_len)
+{
+	struct lrw_struct *lrw_st;
+	int ret = 0;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+
+	netdev_dbg(lrw_st->ndev, "%s: type=%d\n", __func__, type);
+	if (lrw_st->state != LRW_STOP)
+		return -EINVAL;
+
+	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, key, key_len, true);
+	switch (type) {
+	case LRW_APPKEY:
+		swap_bytes(lrw_st->appkey, key, key_len);
+		break;
+	case LRW_NWKSKEY:
+		swap_bytes(lrw_st->nwkskey, key, key_len);
+		break;
+	case LRW_APPSKEY:
+		swap_bytes(lrw_st->appskey, key, key_len);
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(lrw_set_key);
+
+int
+lrw_get_key(struct lrw_hw *hw, u8 type, u8 *key, size_t key_len)
+{
+	struct lrw_struct *lrw_st;
+	int ret = 0;
+
+	lrw_st = container_of(hw, struct lrw_struct, hw);
+
+	netdev_dbg(lrw_st->ndev, "%s: type=%d\n", __func__, type);
+	switch (type) {
+	case LRW_APPKEY:
+		swap_bytes(key, lrw_st->appkey, key_len);
+		break;
+	case LRW_NWKSKEY:
+		swap_bytes(key, lrw_st->nwkskey, key_len);
+		break;
+	case LRW_APPSKEY:
+		swap_bytes(key, lrw_st->appskey, key_len);
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+
+static int
+lrw_if_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+	struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev);
+	struct sockaddr_lorawan *addr;
+	int ret = 0;
+
+	netdev_dbg(ndev, "%s: ioctl file (cmd=0x%X)\n", __func__, cmd);
+
+	/* I/O control by each command */
+	switch (cmd) {
+	/* Set & get the DevAddr, DevEUI and AppEUI */
+	case SIOCSIFADDR:
+		addr = (struct sockaddr_lorawan *)&ifr->ifr_addr;
+		ret = lrw_if_set_addr(lrw_st, addr);
+		break;
+	case SIOCGIFADDR:
+		addr = (struct sockaddr_lorawan *)&ifr->ifr_addr;
+		ret = lrw_if_get_addr(lrw_st, addr);
+		break;
+	default:
+		ret = -ENOTSUPP;
+	}
+
+	return ret;
+}
+
+static int
+lrw_if_set_mac(struct net_device *ndev, void *p)
+{
+	struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev);
+	struct sockaddr *addr = p;
+	__be32 *be_addr;
+
+	be_addr = (__be32 *)addr->sa_data;
+
+	netdev_dbg(ndev, "%s: AF_TYPE:%d set mac address %X\n",
+		   __func__, addr->sa_family, be32_to_cpu(*be_addr));
+
+	if (netif_running(ndev))
+		return -EBUSY;
+
+	lrw_set_devaddr(&lrw_st->hw, be32_to_cpu(*be_addr));
+	memcpy(ndev->dev_addr, be_addr, ndev->addr_len);
+
+	return 0;
+}
+
+static const struct net_device_ops lrw_if_ops = {
+	.ndo_open = lrw_if_up,
+	.ndo_stop = lrw_if_down,
+	.ndo_start_xmit = lrw_if_start_xmit,
+	.ndo_do_ioctl = lrw_if_ioctl,
+	.ndo_set_mac_address = lrw_if_set_mac,
+};
+
+/**
+ * lrw_register_hw - Register as a LoRaWAN compatible device
+ * @hw:		LoRa device going to be registered
+ *
+ * Return:	0 / negative number for success / error number
+ */
+int
+lrw_register_hw(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw);
+	int ret;
+
+	device_initialize(&lrw_st->dev);
+	dev_set_name(&lrw_st->dev, netdev_name(lrw_st->ndev));
+	lrw_st->dev.class = lrw_sys_class;
+	lrw_st->dev.platform_data = lrw_st;
+
+	ret = device_add(&lrw_st->dev);
+	if (ret)
+		goto lrw_register_hw_end;
+
+	/* Add a LoRa device node as a network device */
+	lrw_st->ndev->netdev_ops = &lrw_if_ops;
+	ret = lrw_add_hw(lrw_st);
+	if (!ret)
+		netdev_info(lrw_st->ndev, "register\n");
+
+lrw_register_hw_end:
+	return ret;
+}
+EXPORT_SYMBOL(lrw_register_hw);
+
+/**
+ * lrw_unregister_hw - Unregister the LoRaWAN compatible device
+ * @hw:		LoRa device going to be unregistered
+ */
+void
+lrw_unregister_hw(struct lrw_hw *hw)
+{
+	struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw);
+
+	netdev_info(lrw_st->ndev, "unregister\n");
+
+	/* Stop and remove the LoRaWAM hardware from system */
+	if (lrw_st->state != LRW_STOP)
+		lrw_stop_hw(lrw_st);
+	device_del(&lrw_st->dev);
+	lrw_remove_hw(lrw_st);
+
+	return;
+}
+EXPORT_SYMBOL(lrw_unregister_hw);
+
+static int __init
+lrw_init(void)
+{
+	int err = 0;
+
+	pr_info("%s: module inserted\n", LORAWAN_MODULE_NAME);
+
+	/* Create device class */
+	lrw_sys_class = class_create(THIS_MODULE, LORAWAN_MODULE_NAME);
+	if (IS_ERR(lrw_sys_class)) {
+		pr_err("%s: Failed to create a class of LoRaWAN\n",
+		       LORAWAN_MODULE_NAME);
+		err = PTR_ERR(lrw_sys_class);
+		goto lrw_init_end;
+	}
+
+	pr_debug("%s: class created\n", LORAWAN_MODULE_NAME);
+
+lrw_init_end:
+	return err;
+}
+
+static void __exit
+lrw_exit(void)
+{
+	/* Delete device class */
+	class_destroy(lrw_sys_class);
+	pr_info("%s: module removed\n", LORAWAN_MODULE_NAME);
+}
+
+module_init(lrw_init);
+module_exit(lrw_exit);
+
+MODULE_AUTHOR("Jian-Hong Pan, <starnight@g.ncu.edu.tw>");
+MODULE_DESCRIPTION("LoRaWAN soft MAC kernel module");
+MODULE_LICENSE("Dual BSD/GPL");
-- 
2.19.1

^ permalink raw reply related

* Re: [PATCHv2 net-next 1/4] sctp: define subscribe in sctp_sock as __u16
From: Xin Long @ 2018-11-14 15:11 UTC (permalink / raw)
  To: Neil Horman; +Cc: network dev, linux-sctp, Marcelo Ricardo Leitner, davem
In-Reply-To: <20181113171521.GB7568@neilslaptop.think-freely.org>

On Wed, Nov 14, 2018 at 2:16 AM Neil Horman <nhorman@tuxdriver.com> wrote:
>
> On Tue, Nov 13, 2018 at 02:24:53PM +0800, Xin Long wrote:
> >
> >       /* Default Peer Address Parameters.  These defaults can
> >        * be modified via SCTP_PEER_ADDR_PARAMS
> > @@ -5267,14 +5274,24 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
> >  static int sctp_getsockopt_events(struct sock *sk, int len, char __user *optval,
> >                                 int __user *optlen)
> >  {
> > +     struct sctp_event_subscribe subscribe;
> > +     __u8 *sn_type = (__u8 *)&subscribe;
> > +     int i;
> > +
> >       if (len == 0)
> >               return -EINVAL;
> >       if (len > sizeof(struct sctp_event_subscribe))
> >               len = sizeof(struct sctp_event_subscribe);
> >       if (put_user(len, optlen))
> >               return -EFAULT;
> > -     if (copy_to_user(optval, &sctp_sk(sk)->subscribe, len))
> > +
> > +     for (i = 0; i <= len; i++)
> > +             sn_type[i] = sctp_ulpevent_type_enabled(sctp_sk(sk)->subscribe,
> > +                                                     SCTP_SN_TYPE_BASE + i);
> > +
> This seems like an off by one error.  sctp_event_subscribe has N bytes in it (1
> byte for each event), meaning that that events 0-(N-1) are subscribable.
> Iterating this loop imples that you are going to check N events, overrunning the
> sctp_event_subscribe struct.
you're right, thanks.

>
> Neil
>
> >

^ permalink raw reply

* Re: [PATCH net] ipvs: call ip_vs_dst_notifier before ipv6_dev_notf
From: Xin Long @ 2018-11-14 15:08 UTC (permalink / raw)
  To: kbuild test robot
  Cc: kbuild-all, network dev, netfilter-devel, davem,
	Pablo Neira Ayuso, Hans Schillstrom
In-Reply-To: <201811141232.H4SG8SzP%fengguang.wu@intel.com>

On Wed, Nov 14, 2018 at 1:38 PM kbuild test robot <lkp@intel.com> wrote:
>
> Hi Xin,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on net/master]
>
> url:    https://github.com/0day-ci/linux/commits/Xin-Long/ipvs-call-ip_vs_dst_notifier-before-ipv6_dev_notf/20181114-055727
> config: i386-randconfig-x005-11131818 (attached as .config)
> compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=i386
>
> All errors (new ones prefixed by >>):
>
> >> net/netfilter/ipvs/ip_vs_ctl.c:3983:14: error: 'ADDRCONF_NOTIFY_PRIORITY' undeclared here (not in a function); did you mean 'DEVCONF_NDISC_NOTIFY'?
>      .priority = ADDRCONF_NOTIFY_PRIORITY + 5,
>                  ^~~~~~~~~~~~~~~~~~~~~~~~
>                  DEVCONF_NDISC_NOTIFY
>
> vim +3983 net/netfilter/ipvs/ip_vs_ctl.c
>
>   3980
>   3981  static struct notifier_block ip_vs_dst_notifier = {
>   3982          .notifier_call = ip_vs_dst_event,
> > 3983          .priority = ADDRCONF_NOTIFY_PRIORITY + 5,
>   3984  };
>   3985
This issue only exist on ipv6, I will fix it by simply using
#ifdef CONFIG_IP_VS_IPV6

>
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

^ permalink raw reply

* Re: [PATCH] igb: Fix format with line continuation whitespace
From: Vinicius Costa Gomes @ 2018-11-15  1:04 UTC (permalink / raw)
  To: Joe Perches, Jeff Kirsher
  Cc: David S. Miller, intel-wired-lan, netdev, linux-kernel
In-Reply-To: <1b31c663afa1aa7b3d231917f00f58b9cb604231.camel@perches.com>

Joe Perches <joe@perches.com> writes:

> The line continuation unintentionally adds whitespace so
> instead use a coalesced format to remove the whitespace.
>
> Miscellanea:
>
> o Use a more typical style for ternaries and arguments
>   for this logging message
>
> Signed-off-by: Joe Perches <joe@perches.com>

Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>


Cheers,
--
Vinicius

^ permalink raw reply

* Re: [PATCH][bpf-next] bpf: fix null pointer dereference on pointer offload
From: Jakub Kicinski @ 2018-11-15  0:52 UTC (permalink / raw)
  To: Colin King
  Cc: Alexei Starovoitov, Daniel Borkmann, netdev, kernel-janitors,
	linux-kernel
In-Reply-To: <20181113092926.27081-1-colin.king@canonical.com>

On Tue, 13 Nov 2018 09:29:26 +0000, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>
> 
> Pointer offload is being null checked however the following statement
> dereferences the potentially null pointer offload when assigning
> offload->dev_state.  Fix this by only assigning it if offload is not
> null.
> 
> Detected by CoverityScan, CID#1475437 ("Dereference after null check")
> 
> Fixes: 00db12c3d141 ("bpf: call verifier_prep from its callback in struct bpf_offload_dev")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>

Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>

Thanks!

^ permalink raw reply

* [PATCH net] qed: Fix qed compilation issue when CONFIG_QED_RDMA not defined
From: Denis Bolotin @ 2018-11-14 14:36 UTC (permalink / raw)
  To: davem, netdev; +Cc: ariel.elior, Denis Bolotin

Add a missing semicolon to a line in an empty implementation function.

Signed-off-by: Denis Bolotin <denis.bolotin@cavium.com>
Signed-off-by: Ariel Elior <ariel.elior@cavium.com>
---
 drivers/net/ethernet/qlogic/qed/qed_rdma.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.h b/drivers/net/ethernet/qlogic/qed/qed_rdma.h
index 50d609c..5eec88c 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_rdma.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.h
@@ -183,7 +183,10 @@ struct qed_rdma_qp {
 static inline void qed_rdma_dpm_conf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) {}
 static inline void qed_rdma_dpm_bar(struct qed_hwfn *p_hwfn,
 				    struct qed_ptt *p_ptt) {}
-static inline int qed_rdma_info_alloc(struct qed_hwfn *p_hwfn) {return -EINVAL}
+static inline int qed_rdma_info_alloc(struct qed_hwfn *p_hwfn)
+{
+	return -EINVAL;
+}
 static inline void qed_rdma_info_free(struct qed_hwfn *p_hwfn) {}
 #endif
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH] allow DSCP values in ip rulesB
From: Pavel Balaev @ 2018-11-14 14:30 UTC (permalink / raw)
  To: netdev

Hello, for now IP rules supports only old TOS values and we cannot use
DSCP.

This patch adds support for DSCP values in IP rules:

$ ip r add default via 192.168.0.6 table test
$ ip ru add tos 0x80 table test
$ ip ru
0:	from all lookup local 
32764:	from all tos CS4 lookup test 
32766:	from all lookup main 
32767:	from all lookup default 
$ ip r get fibmatch 8.8.8.9 tos 0x80
default tos CS4 via 192.168.0.6 dev lan table test

Signed-off-by: Pavel Balaev <mail@void.so>
---
 net/ipv4/fib_rules.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index f8eb78d0..7a6c5bfe 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -220,7 +220,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 	int err = -EINVAL;
 	struct fib4_rule *rule4 = (struct fib4_rule *) rule;
 
-	if (frh->tos & ~IPTOS_TOS_MASK) {
+	if (frh->tos & ~(IPTOS_TOS_MASK | IPTOS_PREC_MASK)) {
 		NL_SET_ERR_MSG(extack, "Invalid tos");
 		goto errout;
 	}
-- 
2.18.1

^ permalink raw reply related

* RE: [PATCH] igb: Fix format with line continuation whitespace
From: Brown, Aaron F @ 2018-11-15  0:17 UTC (permalink / raw)
  To: Joe Perches, Kirsher, Jeffrey T
  Cc: David S. Miller, intel-wired-lan@lists.osuosl.org,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <1b31c663afa1aa7b3d231917f00f58b9cb604231.camel@perches.com>

> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Joe Perches
> Sent: Thursday, November 1, 2018 12:04 AM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> Cc: David S. Miller <davem@davemloft.net>; intel-wired-
> lan@lists.osuosl.org; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [PATCH] igb: Fix format with line continuation whitespace
> 
> The line continuation unintentionally adds whitespace so
> instead use a coalesced format to remove the whitespace.
> 
> Miscellanea:
> 
> o Use a more typical style for ternaries and arguments
>   for this logging message
> 
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
>  drivers/net/ethernet/intel/igb/igb_main.c | 13 ++++++-------
>  1 file changed, 6 insertions(+), 7 deletions(-)

Tested-by: Aaron Brown <aaron.f.brown@intel.com>

^ permalink raw reply

* [PATCH 16/16] batman-adv: enable MCAST by default at compile time
From: Simon Wunderlich @ 2018-11-14 14:08 UTC (permalink / raw)
  To: davem
  Cc: netdev, b.a.t.m.a.n, Linus Lüssing, Sven Eckelmann,
	Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Linus Lüssing <linus.luessing@c0d3.blue>

Thanks to rigorous testing in wireless community mesh networks several
issues with multicast entries in the translation table were found and
fixed in the last 1.5 years. Now we see the first larger networks
(a few hundred nodes) with a batman-adv version with multicast
optimizations enabled arising, with no TT / multicast optimization
related issues so far.

Therefore it seems safe to enable multicast optimizations by default.

Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index d6b94559f888..c386e6981416 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -82,6 +82,7 @@ config BATMAN_ADV_NC
 config BATMAN_ADV_MCAST
 	bool "Multicast optimisation"
 	depends on BATMAN_ADV && INET && !(BRIDGE=m && BATMAN_ADV=y)
+	default y
 	help
 	  This option enables the multicast optimisation which aims to
 	  reduce the air overhead while improving the reliability of
-- 
2.11.0

^ permalink raw reply related

* [PATCH 15/16] batman-adv: Move CRC16 dependency to BATMAN_ADV_BLA
From: Simon Wunderlich @ 2018-11-14 14:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The commit ced72933a5e8 ("batman-adv: use CRC32C instead of CRC16 in TT
code") switched the translation table code from crc16 to crc32c. The
(optional) bridge loop avoidance code is the only user of this function.

batman-adv should only select CRC16 when it is actually using it.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 082e96060bc2..d6b94559f888 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -22,7 +22,6 @@
 config BATMAN_ADV
 	tristate "B.A.T.M.A.N. Advanced Meshing Protocol"
 	depends on NET
-	select CRC16
 	select LIBCRC32C
 	help
           B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is
@@ -48,6 +47,7 @@ config BATMAN_ADV_BATMAN_V
 config BATMAN_ADV_BLA
 	bool "Bridge Loop Avoidance"
 	depends on BATMAN_ADV && INET
+	select CRC16
 	default y
 	help
 	  This option enables BLA (Bridge Loop Avoidance), a mechanism
-- 
2.11.0

^ permalink raw reply related

* [PATCH 14/16] batman-adv: Add inconsistent multicast netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. The already existing
generation sequence counter from the hash helper can be used for this
simple hash.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/multicast.c | 51 +++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 23 deletions(-)

diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 86725d792e15..69244e4598f5 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -1365,22 +1365,26 @@ int batadv_mcast_mesh_info_put(struct sk_buff *msg,
  *  to a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @orig_node: originator to dump the multicast flags of
  *
  * Return: 0 or error code.
  */
 static int
-batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid,
+			      struct netlink_callback *cb,
 			      struct batadv_orig_node *orig_node)
 {
 	void *hdr;
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_MCAST_FLAGS);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_MCAST_FLAGS);
 	if (!hdr)
 		return -ENOBUFS;
 
+	genl_dump_check_consistent(cb, hdr);
+
 	if (nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN,
 		    orig_node->orig)) {
 		genlmsg_cancel(msg, hdr);
@@ -1405,21 +1409,26 @@ batadv_mcast_flags_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  *  table to a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
- * @head: bucket to dump
+ * @cb: Control block containing additional options
+ * @hash: hash to dump
+ * @bucket: bucket index to dump
  * @idx_skip: How many entries to skip
  *
  * Return: 0 or error code.
  */
 static int
-batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
-			       struct hlist_head *head, long *idx_skip)
+batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid,
+			       struct netlink_callback *cb,
+			       struct batadv_hashtable *hash,
+			       unsigned int bucket, long *idx_skip)
 {
 	struct batadv_orig_node *orig_node;
 	long idx = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
+	spin_lock_bh(&hash->list_locks[bucket]);
+	cb->seq = atomic_read(&hash->generation) << 1 | 1;
+
+	hlist_for_each_entry(orig_node, &hash->table[bucket], hash_entry) {
 		if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
 			      &orig_node->capa_initialized))
 			continue;
@@ -1427,9 +1436,8 @@ batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 		if (idx < *idx_skip)
 			goto skip;
 
-		if (batadv_mcast_flags_dump_entry(msg, portid, seq,
-						  orig_node)) {
-			rcu_read_unlock();
+		if (batadv_mcast_flags_dump_entry(msg, portid, cb, orig_node)) {
+			spin_unlock_bh(&hash->list_locks[bucket]);
 			*idx_skip = idx;
 
 			return -EMSGSIZE;
@@ -1438,7 +1446,7 @@ batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 skip:
 		idx++;
 	}
-	rcu_read_unlock();
+	spin_unlock_bh(&hash->list_locks[bucket]);
 
 	return 0;
 }
@@ -1447,7 +1455,7 @@ batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
  * __batadv_mcast_flags_dump() - dump multicast flags table to a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @bat_priv: the bat priv with all the soft interface information
  * @bucket: current bucket to dump
  * @idx: index in current bucket to the next entry to dump
@@ -1455,19 +1463,17 @@ batadv_mcast_flags_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
  * Return: 0 or error code.
  */
 static int
-__batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid, u32 seq,
+__batadv_mcast_flags_dump(struct sk_buff *msg, u32 portid,
+			  struct netlink_callback *cb,
 			  struct batadv_priv *bat_priv, long *bucket, long *idx)
 {
 	struct batadv_hashtable *hash = bat_priv->orig_hash;
 	long bucket_tmp = *bucket;
-	struct hlist_head *head;
 	long idx_tmp = *idx;
 
 	while (bucket_tmp < hash->size) {
-		head = &hash->table[bucket_tmp];
-
-		if (batadv_mcast_flags_dump_bucket(msg, portid, seq, head,
-						   &idx_tmp))
+		if (batadv_mcast_flags_dump_bucket(msg, portid, cb, hash,
+						   *bucket, &idx_tmp))
 			break;
 
 		bucket_tmp++;
@@ -1550,8 +1556,7 @@ int batadv_mcast_flags_dump(struct sk_buff *msg, struct netlink_callback *cb)
 		return ret;
 
 	bat_priv = netdev_priv(primary_if->soft_iface);
-	ret = __batadv_mcast_flags_dump(msg, portid, cb->nlh->nlmsg_seq,
-					bat_priv, bucket, idx);
+	ret = __batadv_mcast_flags_dump(msg, portid, cb, bat_priv, bucket, idx);
 
 	batadv_hardif_put(primary_if);
 	return ret;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 13/16] batman-adv: Add inconsistent local TT netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. The already existing
generation sequence counter from the hash helper can be used for this
simple hash.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/translation-table.c | 41 +++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index d21624c44665..8dcd4968cde7 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -1145,14 +1145,15 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
  * batadv_tt_local_dump_entry() - Dump one TT local entry into a message
  * @msg :Netlink message to dump into
  * @portid: Port making netlink request
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @bat_priv: The bat priv with all the soft interface information
  * @common: tt local & tt global common data
  *
  * Return: Error code, or 0 on success
  */
 static int
-batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
+			   struct netlink_callback *cb,
 			   struct batadv_priv *bat_priv,
 			   struct batadv_tt_common_entry *common)
 {
@@ -1173,12 +1174,14 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 
 	batadv_softif_vlan_put(vlan);
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI,
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family,  NLM_F_MULTI,
 			  BATADV_CMD_GET_TRANSTABLE_LOCAL);
 	if (!hdr)
 		return -ENOBUFS;
 
+	genl_dump_check_consistent(cb, hdr);
+
 	if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
 	    nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
 	    nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
@@ -1201,34 +1204,39 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  * batadv_tt_local_dump_bucket() - Dump one TT local bucket into a message
  * @msg: Netlink message to dump into
  * @portid: Port making netlink request
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @bat_priv: The bat priv with all the soft interface information
- * @head: Pointer to the list containing the local tt entries
+ * @hash: hash to dump
+ * @bucket: bucket index to dump
  * @idx_s: Number of entries to skip
  *
  * Return: Error code, or 0 on success
  */
 static int
-batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_tt_local_dump_bucket(struct sk_buff *msg, u32 portid,
+			    struct netlink_callback *cb,
 			    struct batadv_priv *bat_priv,
-			    struct hlist_head *head, int *idx_s)
+			    struct batadv_hashtable *hash, unsigned int bucket,
+			    int *idx_s)
 {
 	struct batadv_tt_common_entry *common;
 	int idx = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(common, head, hash_entry) {
+	spin_lock_bh(&hash->list_locks[bucket]);
+	cb->seq = atomic_read(&hash->generation) << 1 | 1;
+
+	hlist_for_each_entry(common, &hash->table[bucket], hash_entry) {
 		if (idx++ < *idx_s)
 			continue;
 
-		if (batadv_tt_local_dump_entry(msg, portid, seq, bat_priv,
+		if (batadv_tt_local_dump_entry(msg, portid, cb, bat_priv,
 					       common)) {
-			rcu_read_unlock();
+			spin_unlock_bh(&hash->list_locks[bucket]);
 			*idx_s = idx - 1;
 			return -EMSGSIZE;
 		}
 	}
-	rcu_read_unlock();
+	spin_unlock_bh(&hash->list_locks[bucket]);
 
 	*idx_s = 0;
 	return 0;
@@ -1248,7 +1256,6 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	struct batadv_priv *bat_priv;
 	struct batadv_hard_iface *primary_if = NULL;
 	struct batadv_hashtable *hash;
-	struct hlist_head *head;
 	int ret;
 	int ifindex;
 	int bucket = cb->args[0];
@@ -1276,10 +1283,8 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	hash = bat_priv->tt.local_hash;
 
 	while (bucket < hash->size) {
-		head = &hash->table[bucket];
-
-		if (batadv_tt_local_dump_bucket(msg, portid, cb->nlh->nlmsg_seq,
-						bat_priv, head, &idx))
+		if (batadv_tt_local_dump_bucket(msg, portid, cb, bat_priv,
+						hash, bucket, &idx))
 			break;
 
 		bucket++;
-- 
2.11.0

^ permalink raw reply related

* [PATCH 12/16] batman-adv: Add inconsistent dat netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:08 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. The already existing
generation sequence counter from the hash helper can be used for this
simple hash.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/distributed-arp-table.c | 42 +++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 19 deletions(-)

diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index a60bacf7120b..b9ffe1826527 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -863,23 +863,27 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
  *  netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @dat_entry: entry to dump
  *
  * Return: 0 or error code.
  */
 static int
-batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
+			    struct netlink_callback *cb,
 			    struct batadv_dat_entry *dat_entry)
 {
 	int msecs;
 	void *hdr;
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_DAT_CACHE);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_DAT_CACHE);
 	if (!hdr)
 		return -ENOBUFS;
 
+	genl_dump_check_consistent(cb, hdr);
+
 	msecs = jiffies_to_msecs(jiffies - dat_entry->last_update);
 
 	if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,
@@ -901,27 +905,31 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  *  a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
- * @head: bucket to dump
+ * @cb: Control block containing additional options
+ * @hash: hash to dump
+ * @bucket: bucket index to dump
  * @idx_skip: How many entries to skip
  *
  * Return: 0 or error code.
  */
 static int
-batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
-			     struct hlist_head *head, int *idx_skip)
+batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid,
+			     struct netlink_callback *cb,
+			     struct batadv_hashtable *hash, unsigned int bucket,
+			     int *idx_skip)
 {
 	struct batadv_dat_entry *dat_entry;
 	int idx = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(dat_entry, head, hash_entry) {
+	spin_lock_bh(&hash->list_locks[bucket]);
+	cb->seq = atomic_read(&hash->generation) << 1 | 1;
+
+	hlist_for_each_entry(dat_entry, &hash->table[bucket], hash_entry) {
 		if (idx < *idx_skip)
 			goto skip;
 
-		if (batadv_dat_cache_dump_entry(msg, portid, seq,
-						dat_entry)) {
-			rcu_read_unlock();
+		if (batadv_dat_cache_dump_entry(msg, portid, cb, dat_entry)) {
+			spin_unlock_bh(&hash->list_locks[bucket]);
 			*idx_skip = idx;
 
 			return -EMSGSIZE;
@@ -930,7 +938,7 @@ batadv_dat_cache_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 skip:
 		idx++;
 	}
-	rcu_read_unlock();
+	spin_unlock_bh(&hash->list_locks[bucket]);
 
 	return 0;
 }
@@ -951,7 +959,6 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	struct batadv_hashtable *hash;
 	struct batadv_priv *bat_priv;
 	int bucket = cb->args[0];
-	struct hlist_head *head;
 	int idx = cb->args[1];
 	int ifindex;
 	int ret = 0;
@@ -977,10 +984,7 @@ int batadv_dat_cache_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	}
 
 	while (bucket < hash->size) {
-		head = &hash->table[bucket];
-
-		if (batadv_dat_cache_dump_bucket(msg, portid,
-						 cb->nlh->nlmsg_seq, head,
+		if (batadv_dat_cache_dump_bucket(msg, portid, cb, hash, bucket,
 						 &idx))
 			break;
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 11/16] batman-adv: Add inconsistent claim netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. The already existing
generation sequence counter from the hash helper can be used for this
simple hash.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/bridge_loop_avoidance.c | 41 +++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 9f3747346d29..5fdde2947802 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -2094,14 +2094,15 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset)
  * to a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @primary_if: primary interface
  * @claim: entry to dump
  *
  * Return: 0 or error code.
  */
 static int
-batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid,
+			    struct netlink_callback *cb,
 			    struct batadv_hard_iface *primary_if,
 			    struct batadv_bla_claim *claim)
 {
@@ -2111,13 +2112,16 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 	void *hdr;
 	int ret = -EINVAL;
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_BLA_CLAIM);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_BLA_CLAIM);
 	if (!hdr) {
 		ret = -ENOBUFS;
 		goto out;
 	}
 
+	genl_dump_check_consistent(cb, hdr);
+
 	is_own = batadv_compare_eth(claim->backbone_gw->orig,
 				    primary_addr);
 
@@ -2153,28 +2157,33 @@ batadv_bla_claim_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  * to a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @primary_if: primary interface
- * @head: bucket to dump
+ * @hash: hash to dump
+ * @bucket: bucket index to dump
  * @idx_skip: How many entries to skip
  *
  * Return: always 0.
  */
 static int
-batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid,
+			     struct netlink_callback *cb,
 			     struct batadv_hard_iface *primary_if,
-			     struct hlist_head *head, int *idx_skip)
+			     struct batadv_hashtable *hash, unsigned int bucket,
+			     int *idx_skip)
 {
 	struct batadv_bla_claim *claim;
 	int idx = 0;
 	int ret = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(claim, head, hash_entry) {
+	spin_lock_bh(&hash->list_locks[bucket]);
+	cb->seq = atomic_read(&hash->generation) << 1 | 1;
+
+	hlist_for_each_entry(claim, &hash->table[bucket], hash_entry) {
 		if (idx++ < *idx_skip)
 			continue;
 
-		ret = batadv_bla_claim_dump_entry(msg, portid, seq,
+		ret = batadv_bla_claim_dump_entry(msg, portid, cb,
 						  primary_if, claim);
 		if (ret) {
 			*idx_skip = idx - 1;
@@ -2184,7 +2193,7 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 
 	*idx_skip = 0;
 unlock:
-	rcu_read_unlock();
+	spin_unlock_bh(&hash->list_locks[bucket]);
 	return ret;
 }
 
@@ -2204,7 +2213,6 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	struct batadv_hashtable *hash;
 	struct batadv_priv *bat_priv;
 	int bucket = cb->args[0];
-	struct hlist_head *head;
 	int idx = cb->args[1];
 	int ifindex;
 	int ret = 0;
@@ -2230,11 +2238,8 @@ int batadv_bla_claim_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	}
 
 	while (bucket < hash->size) {
-		head = &hash->table[bucket];
-
-		if (batadv_bla_claim_dump_bucket(msg, portid,
-						 cb->nlh->nlmsg_seq,
-						 primary_if, head, &idx))
+		if (batadv_bla_claim_dump_bucket(msg, portid, cb, primary_if,
+						 hash, bucket, &idx))
 			break;
 		bucket++;
 	}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 10/16] batman-adv: Add inconsistent backbone netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. The already existing
generation sequence counter from the hash helper can be used for this
simple hash.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/bridge_loop_avoidance.c | 41 +++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 5f1aeeded0e3..9f3747346d29 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -2325,14 +2325,15 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset)
  *  netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @primary_if: primary interface
  * @backbone_gw: entry to dump
  *
  * Return: 0 or error code.
  */
 static int
-batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid,
+			       struct netlink_callback *cb,
 			       struct batadv_hard_iface *primary_if,
 			       struct batadv_bla_backbone_gw *backbone_gw)
 {
@@ -2343,13 +2344,16 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 	void *hdr;
 	int ret = -EINVAL;
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_BLA_BACKBONE);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_BLA_BACKBONE);
 	if (!hdr) {
 		ret = -ENOBUFS;
 		goto out;
 	}
 
+	genl_dump_check_consistent(cb, hdr);
+
 	is_own = batadv_compare_eth(backbone_gw->orig, primary_addr);
 
 	spin_lock_bh(&backbone_gw->crc_lock);
@@ -2386,28 +2390,33 @@ batadv_bla_backbone_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
  *  a netlink socket
  * @msg: buffer for the message
  * @portid: netlink port
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @primary_if: primary interface
- * @head: bucket to dump
+ * @hash: hash to dump
+ * @bucket: bucket index to dump
  * @idx_skip: How many entries to skip
  *
  * Return: always 0.
  */
 static int
-batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid,
+				struct netlink_callback *cb,
 				struct batadv_hard_iface *primary_if,
-				struct hlist_head *head, int *idx_skip)
+				struct batadv_hashtable *hash,
+				unsigned int bucket, int *idx_skip)
 {
 	struct batadv_bla_backbone_gw *backbone_gw;
 	int idx = 0;
 	int ret = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
+	spin_lock_bh(&hash->list_locks[bucket]);
+	cb->seq = atomic_read(&hash->generation) << 1 | 1;
+
+	hlist_for_each_entry(backbone_gw, &hash->table[bucket], hash_entry) {
 		if (idx++ < *idx_skip)
 			continue;
 
-		ret = batadv_bla_backbone_dump_entry(msg, portid, seq,
+		ret = batadv_bla_backbone_dump_entry(msg, portid, cb,
 						     primary_if, backbone_gw);
 		if (ret) {
 			*idx_skip = idx - 1;
@@ -2417,7 +2426,7 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 
 	*idx_skip = 0;
 unlock:
-	rcu_read_unlock();
+	spin_unlock_bh(&hash->list_locks[bucket]);
 	return ret;
 }
 
@@ -2437,7 +2446,6 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	struct batadv_hashtable *hash;
 	struct batadv_priv *bat_priv;
 	int bucket = cb->args[0];
-	struct hlist_head *head;
 	int idx = cb->args[1];
 	int ifindex;
 	int ret = 0;
@@ -2463,11 +2471,8 @@ int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)
 	}
 
 	while (bucket < hash->size) {
-		head = &hash->table[bucket];
-
-		if (batadv_bla_backbone_dump_bucket(msg, portid,
-						    cb->nlh->nlmsg_seq,
-						    primary_if, head, &idx))
+		if (batadv_bla_backbone_dump_bucket(msg, portid, cb, primary_if,
+						    hash, bucket, &idx))
 			break;
 		bucket++;
 	}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 09/16] batman-adv: Store modification counter via hash helpers
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

Multiple datastructures use the hash helper functions to add and remove
entries from the simple hlist based hashes. These are often also dumped to
userspace via netlink and thus should have a generation sequence counter.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/hash.c | 2 ++
 net/batman-adv/hash.h | 6 ++++++
 2 files changed, 8 insertions(+)

diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c
index 7b49e4001778..9194f4d891b1 100644
--- a/net/batman-adv/hash.c
+++ b/net/batman-adv/hash.c
@@ -32,6 +32,8 @@ static void batadv_hash_init(struct batadv_hashtable *hash)
 		INIT_HLIST_HEAD(&hash->table[i]);
 		spin_lock_init(&hash->list_locks[i]);
 	}
+
+	atomic_set(&hash->generation, 0);
 }
 
 /**
diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h
index 9490a7ca2ba6..0e36fa1c7c3e 100644
--- a/net/batman-adv/hash.h
+++ b/net/batman-adv/hash.h
@@ -21,6 +21,7 @@
 
 #include "main.h"
 
+#include <linux/atomic.h>
 #include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/rculist.h>
@@ -58,6 +59,9 @@ struct batadv_hashtable {
 
 	/** @size: size of hashtable */
 	u32 size;
+
+	/** @generation: current (generation) sequence number */
+	atomic_t generation;
 };
 
 /* allocates and clears the hash */
@@ -112,6 +116,7 @@ static inline int batadv_hash_add(struct batadv_hashtable *hash,
 
 	/* no duplicate found in list, add new element */
 	hlist_add_head_rcu(data_node, head);
+	atomic_inc(&hash->generation);
 
 	ret = 0;
 
@@ -154,6 +159,7 @@ static inline void *batadv_hash_remove(struct batadv_hashtable *hash,
 
 		data_save = node;
 		hlist_del_rcu(node);
+		atomic_inc(&hash->generation);
 		break;
 	}
 	spin_unlock_bh(&hash->list_locks[index]);
-- 
2.11.0

^ permalink raw reply related

* [PATCH 08/16] batman-adv: Add inconsistent hardif netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. And an external generation
sequence counter is introduced which tracks all modifications of the list.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/hard-interface.c |  3 +++
 net/batman-adv/main.c           |  1 +
 net/batman-adv/main.h           |  1 +
 net/batman-adv/netlink.c        | 24 ++++++++++++++----------
 4 files changed, 19 insertions(+), 10 deletions(-)

diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 781c5b6e6e8e..508f4416dfc9 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -951,6 +951,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
 	batadv_check_known_mac_addr(hard_iface->net_dev);
 	kref_get(&hard_iface->refcount);
 	list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
+	batadv_hardif_generation++;
 
 	return hard_iface;
 
@@ -993,6 +994,7 @@ void batadv_hardif_remove_interfaces(void)
 	list_for_each_entry_safe(hard_iface, hard_iface_tmp,
 				 &batadv_hardif_list, list) {
 		list_del_rcu(&hard_iface->list);
+		batadv_hardif_generation++;
 		batadv_hardif_remove_interface(hard_iface);
 	}
 	rtnl_unlock();
@@ -1054,6 +1056,7 @@ static int batadv_hard_if_event(struct notifier_block *this,
 	case NETDEV_UNREGISTER:
 	case NETDEV_PRE_TYPE_CHANGE:
 		list_del_rcu(&hard_iface->list);
+		batadv_hardif_generation++;
 
 		batadv_hardif_remove_interface(hard_iface);
 		break;
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index c75e47826949..d1ed839fd32b 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -74,6 +74,7 @@
  * list traversals just rcu-locked
  */
 struct list_head batadv_hardif_list;
+unsigned int batadv_hardif_generation;
 static int (*batadv_rx_handler[256])(struct sk_buff *skb,
 				     struct batadv_hard_iface *recv_if);
 
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index b68a41190eb0..b572066325e4 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -247,6 +247,7 @@ static inline int batadv_print_vid(unsigned short vid)
 }
 
 extern struct list_head batadv_hardif_list;
+extern unsigned int batadv_hardif_generation;
 
 extern unsigned char batadv_broadcast_addr[];
 extern struct workqueue_struct *batadv_event_workqueue;
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 0d9459b69bdb..2dc3304cee54 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -29,11 +29,11 @@
 #include <linux/if_ether.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/netlink.h>
 #include <linux/printk.h>
-#include <linux/rculist.h>
-#include <linux/rcupdate.h>
+#include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
@@ -445,23 +445,27 @@ batadv_netlink_tp_meter_cancel(struct sk_buff *skb, struct genl_info *info)
  * batadv_netlink_dump_hardif_entry() - Dump one hard interface into a message
  * @msg: Netlink message to dump into
  * @portid: Port making netlink request
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @hard_iface: Hard interface to dump
  *
  * Return: error code, or 0 on success
  */
 static int
-batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid, u32 seq,
+batadv_netlink_dump_hardif_entry(struct sk_buff *msg, u32 portid,
+				 struct netlink_callback *cb,
 				 struct batadv_hard_iface *hard_iface)
 {
 	struct net_device *net_dev = hard_iface->net_dev;
 	void *hdr;
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family, NLM_F_MULTI,
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
 			  BATADV_CMD_GET_HARDIFS);
 	if (!hdr)
 		return -EMSGSIZE;
 
+	genl_dump_check_consistent(cb, hdr);
+
 	if (nla_put_u32(msg, BATADV_ATTR_HARD_IFINDEX,
 			net_dev->ifindex) ||
 	    nla_put_string(msg, BATADV_ATTR_HARD_IFNAME,
@@ -498,7 +502,6 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
 	struct batadv_hard_iface *hard_iface;
 	int ifindex;
 	int portid = NETLINK_CB(cb->skb).portid;
-	int seq = cb->nlh->nlmsg_seq;
 	int skip = cb->args[0];
 	int i = 0;
 
@@ -516,23 +519,24 @@ batadv_netlink_dump_hardifs(struct sk_buff *msg, struct netlink_callback *cb)
 		return -ENODEV;
 	}
 
-	rcu_read_lock();
+	rtnl_lock();
+	cb->seq = batadv_hardif_generation << 1 | 1;
 
-	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
+	list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
 		if (hard_iface->soft_iface != soft_iface)
 			continue;
 
 		if (i++ < skip)
 			continue;
 
-		if (batadv_netlink_dump_hardif_entry(msg, portid, seq,
+		if (batadv_netlink_dump_hardif_entry(msg, portid, cb,
 						     hard_iface)) {
 			i--;
 			break;
 		}
 	}
 
-	rcu_read_unlock();
+	rtnl_unlock();
 
 	dev_put(soft_iface);
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH 07/16] batman-adv: Add inconsistent gateway netlink dump detection
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The netlink dump functionality transfers a large number of entries from the
kernel to userspace. It is rather likely that the transfer has to
interrupted and later continued. During that time, it can happen that
either new entries are added or removed. The userspace could than either
receive some entries multiple times or miss entries.

Commit 670dc2833d14 ("netlink: advertise incomplete dumps") introduced a
mechanism to inform userspace about this problem. Userspace can then decide
whether it is necessary or not to retry dumping the information again.

The netlink dump functions have to be switched to exclusive locks to avoid
changes while the current message is prepared. And an external generation
sequence counter is introduced which tracks all modifications of the list.

Reported-by: Matthias Schiffer <mschiffer@universe-factory.net>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/bat_iv_ogm.c     | 24 +++++++++++++++---------
 net/batman-adv/bat_v.c          | 26 +++++++++++++++++---------
 net/batman-adv/gateway_client.c |  3 +++
 net/batman-adv/main.c           |  2 ++
 net/batman-adv/types.h          |  5 ++++-
 5 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 1d31ac84dec7..f97e566f0402 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -2584,13 +2584,14 @@ static void batadv_iv_gw_print(struct batadv_priv *bat_priv,
  * batadv_iv_gw_dump_entry() - Dump a gateway into a message
  * @msg: Netlink message to dump into
  * @portid: Port making netlink request
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @bat_priv: The bat priv with all the soft interface information
  * @gw_node: Gateway to be dumped
  *
  * Return: Error code, or 0 on success
  */
-static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid,
+				   struct netlink_callback *cb,
 				   struct batadv_priv *bat_priv,
 				   struct batadv_gw_node *gw_node)
 {
@@ -2610,13 +2611,16 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 
 	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_GATEWAYS);
 	if (!hdr) {
 		ret = -ENOBUFS;
 		goto out;
 	}
 
+	genl_dump_check_consistent(cb, hdr);
+
 	ret = -EMSGSIZE;
 
 	if (curr_gw == gw_node)
@@ -2667,13 +2671,15 @@ static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
 	int idx_skip = cb->args[0];
 	int idx = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
+	spin_lock_bh(&bat_priv->gw.list_lock);
+	cb->seq = bat_priv->gw.generation << 1 | 1;
+
+	hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
 		if (idx++ < idx_skip)
 			continue;
 
-		if (batadv_iv_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
-					    bat_priv, gw_node)) {
+		if (batadv_iv_gw_dump_entry(msg, portid, cb, bat_priv,
+					    gw_node)) {
 			idx_skip = idx - 1;
 			goto unlock;
 		}
@@ -2681,7 +2687,7 @@ static void batadv_iv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
 
 	idx_skip = idx;
 unlock:
-	rcu_read_unlock();
+	spin_unlock_bh(&bat_priv->gw.list_lock);
 
 	cb->args[0] = idx_skip;
 }
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index 6baec4e68898..90e33f84d37a 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -27,11 +27,13 @@
 #include <linux/jiffies.h>
 #include <linux/kernel.h>
 #include <linux/kref.h>
+#include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/netlink.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
 #include <linux/seq_file.h>
+#include <linux/spinlock.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
@@ -915,13 +917,14 @@ static void batadv_v_gw_print(struct batadv_priv *bat_priv,
  * batadv_v_gw_dump_entry() - Dump a gateway into a message
  * @msg: Netlink message to dump into
  * @portid: Port making netlink request
- * @seq: Sequence number of netlink message
+ * @cb: Control block containing additional options
  * @bat_priv: The bat priv with all the soft interface information
  * @gw_node: Gateway to be dumped
  *
  * Return: Error code, or 0 on success
  */
-static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
+static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid,
+				  struct netlink_callback *cb,
 				  struct batadv_priv *bat_priv,
 				  struct batadv_gw_node *gw_node)
 {
@@ -941,13 +944,16 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
 
 	curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
-	hdr = genlmsg_put(msg, portid, seq, &batadv_netlink_family,
-			  NLM_F_MULTI, BATADV_CMD_GET_GATEWAYS);
+	hdr = genlmsg_put(msg, portid, cb->nlh->nlmsg_seq,
+			  &batadv_netlink_family, NLM_F_MULTI,
+			  BATADV_CMD_GET_GATEWAYS);
 	if (!hdr) {
 		ret = -ENOBUFS;
 		goto out;
 	}
 
+	genl_dump_check_consistent(cb, hdr);
+
 	ret = -EMSGSIZE;
 
 	if (curr_gw == gw_node) {
@@ -1018,13 +1024,15 @@ static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
 	int idx_skip = cb->args[0];
 	int idx = 0;
 
-	rcu_read_lock();
-	hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.gateway_list, list) {
+	spin_lock_bh(&bat_priv->gw.list_lock);
+	cb->seq = bat_priv->gw.generation << 1 | 1;
+
+	hlist_for_each_entry(gw_node, &bat_priv->gw.gateway_list, list) {
 		if (idx++ < idx_skip)
 			continue;
 
-		if (batadv_v_gw_dump_entry(msg, portid, cb->nlh->nlmsg_seq,
-					   bat_priv, gw_node)) {
+		if (batadv_v_gw_dump_entry(msg, portid, cb, bat_priv,
+					   gw_node)) {
 			idx_skip = idx - 1;
 			goto unlock;
 		}
@@ -1032,7 +1040,7 @@ static void batadv_v_gw_dump(struct sk_buff *msg, struct netlink_callback *cb,
 
 	idx_skip = idx;
 unlock:
-	rcu_read_unlock();
+	spin_unlock_bh(&bat_priv->gw.list_lock);
 
 	cb->args[0] = idx_skip;
 }
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index 140c61a3f1ec..9d8e5eda2314 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -377,6 +377,7 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
 
 	kref_get(&gw_node->refcount);
 	hlist_add_head_rcu(&gw_node->list, &bat_priv->gw.gateway_list);
+	bat_priv->gw.generation++;
 
 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
 		   "Found new gateway %pM -> gw bandwidth: %u.%u/%u.%u MBit\n",
@@ -472,6 +473,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv,
 		if (!hlist_unhashed(&gw_node->list)) {
 			hlist_del_init_rcu(&gw_node->list);
 			batadv_gw_node_put(gw_node);
+			bat_priv->gw.generation++;
 		}
 		spin_unlock_bh(&bat_priv->gw.list_lock);
 
@@ -518,6 +520,7 @@ void batadv_gw_node_free(struct batadv_priv *bat_priv)
 				  &bat_priv->gw.gateway_list, list) {
 		hlist_del_init_rcu(&gw_node->list);
 		batadv_gw_node_put(gw_node);
+		bat_priv->gw.generation++;
 	}
 	spin_unlock_bh(&bat_priv->gw.list_lock);
 }
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 69c0d85bceb3..c75e47826949 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -186,6 +186,8 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	INIT_HLIST_HEAD(&bat_priv->softif_vlan_list);
 	INIT_HLIST_HEAD(&bat_priv->tp_list);
 
+	bat_priv->gw.generation = 0;
+
 	ret = batadv_v_mesh_init(bat_priv);
 	if (ret < 0)
 		goto err;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 45b5592de816..cbe17da36fcb 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -1096,12 +1096,15 @@ struct batadv_priv_gw {
 	/** @gateway_list: list of available gateway nodes */
 	struct hlist_head gateway_list;
 
-	/** @list_lock: lock protecting gateway_list & curr_gw */
+	/** @list_lock: lock protecting gateway_list, curr_gw, generation */
 	spinlock_t list_lock;
 
 	/** @curr_gw: pointer to currently selected gateway node */
 	struct batadv_gw_node __rcu *curr_gw;
 
+	/** @generation: current (generation) sequence number */
+	unsigned int generation;
+
 	/**
 	 * @mode: gateway operation: off, client or server (see batadv_gw_modes)
 	 */
-- 
2.11.0

^ permalink raw reply related

* [PATCH 05/16] batman-adv: Allow to use BATMAN_ADV_DEBUG without BATMAN_ADV_DEBUGFS
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The BATMAN_ADV_DEBUGFS portion of batman-adv is marked as deprecated. Thus
all required functionality should be available without it. The debug log
was already modified to also output via the kernel tracing function but
still retained its BATMAN_ADV_DEBUGFS functionality.

Separate the entry point for the debug log from the debugfs portions to
make it possible to build with BATMAN_ADV_DEBUG and without
BATMAN_ADV_DEBUGFS.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/Kconfig |  2 +-
 net/batman-adv/log.c   | 60 +++++++++++++++++++++++++++-----------------------
 2 files changed, 34 insertions(+), 28 deletions(-)

diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index f75816f58107..7b0e1fcddfa7 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -100,7 +100,7 @@ config BATMAN_ADV_DEBUGFS
 
 config BATMAN_ADV_DEBUG
 	bool "B.A.T.M.A.N. debugging"
-	depends on BATMAN_ADV_DEBUGFS
+	depends on BATMAN_ADV
 	help
 	  This is an option for use by developers; most people should
 	  say N here. This enables compilation of support for
diff --git a/net/batman-adv/log.c b/net/batman-adv/log.c
index 6beb5f067810..02e55b78132f 100644
--- a/net/batman-adv/log.c
+++ b/net/batman-adv/log.c
@@ -43,6 +43,8 @@
 #include "debugfs.h"
 #include "trace.h"
 
+#ifdef CONFIG_BATMAN_ADV_DEBUGFS
+
 #define BATADV_LOG_BUFF_MASK (batadv_log_buff_len - 1)
 
 static const int batadv_log_buff_len = BATADV_LOG_BUF_LEN;
@@ -92,33 +94,6 @@ static int batadv_fdebug_log(struct batadv_priv_debug_log *debug_log,
 	return 0;
 }
 
-/**
- * batadv_debug_log() - Add debug log entry
- * @bat_priv: the bat priv with all the soft interface information
- * @fmt: format string
- *
- * Return: 0 on success or negative error number in case of failure
- */
-int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
-{
-	struct va_format vaf;
-	va_list args;
-
-	va_start(args, fmt);
-
-	vaf.fmt = fmt;
-	vaf.va = &args;
-
-	batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV",
-			  jiffies_to_msecs(jiffies), &vaf);
-
-	trace_batadv_dbg(bat_priv, &vaf);
-
-	va_end(args);
-
-	return 0;
-}
-
 static int batadv_log_open(struct inode *inode, struct file *file)
 {
 	if (!try_module_get(THIS_MODULE))
@@ -259,3 +234,34 @@ void batadv_debug_log_cleanup(struct batadv_priv *bat_priv)
 	kfree(bat_priv->debug_log);
 	bat_priv->debug_log = NULL;
 }
+
+#endif /* CONFIG_BATMAN_ADV_DEBUGFS */
+
+/**
+ * batadv_debug_log() - Add debug log entry
+ * @bat_priv: the bat priv with all the soft interface information
+ * @fmt: format string
+ *
+ * Return: 0 on success or negative error number in case of failure
+ */
+int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+#ifdef CONFIG_BATMAN_ADV_DEBUGFS
+	batadv_fdebug_log(bat_priv->debug_log, "[%10u] %pV",
+			  jiffies_to_msecs(jiffies), &vaf);
+#endif
+
+	trace_batadv_dbg(bat_priv, &vaf);
+
+	va_end(args);
+
+	return 0;
+}
-- 
2.11.0

^ permalink raw reply related

* [PATCH 06/16] batman-adv: Fix description for BATMAN_ADV_DEBUG
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The debug messages of batman-adv are not printed to the kernel log at all
but can be stored (depending on the compile setting) in the tracing buffer
or the batadv specific log buffer. There is also no debug module parameter
but a batadv netdev specific log_level setting to enable/disable different
classes of debug messages at runtime.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/Kconfig | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/batman-adv/Kconfig b/net/batman-adv/Kconfig
index 7b0e1fcddfa7..082e96060bc2 100644
--- a/net/batman-adv/Kconfig
+++ b/net/batman-adv/Kconfig
@@ -104,8 +104,9 @@ config BATMAN_ADV_DEBUG
 	help
 	  This is an option for use by developers; most people should
 	  say N here. This enables compilation of support for
-	  outputting debugging information to the kernel log. The
-	  output is controlled via the module parameter debug.
+	  outputting debugging information to the debugfs log or tracing
+	  buffer. The output is controlled via the batadv netdev specific
+	  log_level setting.
 
 config BATMAN_ADV_TRACING
 	bool "B.A.T.M.A.N. tracing support"
-- 
2.11.0

^ permalink raw reply related

* [PATCH 04/16] batman-adv: Improve includes for trace functionality
From: Simon Wunderlich @ 2018-11-14 14:07 UTC (permalink / raw)
  To: davem; +Cc: netdev, b.a.t.m.a.n, Sven Eckelmann, Simon Wunderlich
In-Reply-To: <20181114140804.18381-1-sw@simonwunderlich.de>

From: Sven Eckelmann <sven@narfation.org>

The batadv_dbg trace event uses different functionality and datastructures
which are not directly associated with the trace infrastructure. It should
not be expected that the trace headers indirectly provide them and instead
include the required headers directly.

Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
 net/batman-adv/trace.c | 2 --
 net/batman-adv/trace.h | 6 ++++++
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/net/batman-adv/trace.c b/net/batman-adv/trace.c
index 3d57f9981f25..8e1024217cff 100644
--- a/net/batman-adv/trace.c
+++ b/net/batman-adv/trace.c
@@ -16,7 +16,5 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <linux/module.h>
-
 #define CREATE_TRACE_POINTS
 #include "trace.h"
diff --git a/net/batman-adv/trace.h b/net/batman-adv/trace.h
index 3acda26a30ca..104784be94d7 100644
--- a/net/batman-adv/trace.h
+++ b/net/batman-adv/trace.h
@@ -21,7 +21,13 @@
 
 #include "main.h"
 
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/percpu.h>
+#include <linux/printk.h>
 #include <linux/tracepoint.h>
+#include <linux/types.h>
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM batadv
-- 
2.11.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox