* Re: [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
From: Jason Wang @ 2018-11-06 4:00 UTC (permalink / raw)
To: jiangyiwen, stefanha; +Cc: netdev, kvm, virtualization
In-Reply-To: <5BDFF57C.5020106@huawei.com>
On 2018/11/5 下午3:47, jiangyiwen wrote:
> Guest receive mergeable rx buffer, it can merge
> scatter rx buffer into a big buffer and then copy
> to user space.
>
> Signed-off-by: Yiwen Jiang <jiangyiwen@huawei.com>
> ---
> include/linux/virtio_vsock.h | 9 ++++
> net/vmw_vsock/virtio_transport.c | 75 +++++++++++++++++++++++++++++----
> net/vmw_vsock/virtio_transport_common.c | 59 ++++++++++++++++++++++----
> 3 files changed, 127 insertions(+), 16 deletions(-)
>
> diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
> index da9e1fe..6be3cd7 100644
> --- a/include/linux/virtio_vsock.h
> +++ b/include/linux/virtio_vsock.h
> @@ -13,6 +13,8 @@
> #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4)
> #define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL
> #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64)
> +/* virtio_vsock_pkt + max_pkt_len(default MAX_PKT_BUF_SIZE) */
> +#define VIRTIO_VSOCK_MAX_MRG_BUF_NUM ((VIRTIO_VSOCK_MAX_PKT_BUF_SIZE / PAGE_SIZE) + 1)
>
> /* Virtio-vsock feature */
> #define VIRTIO_VSOCK_F_MRG_RXBUF 0 /* Host can merge receive buffers. */
> @@ -48,6 +50,11 @@ struct virtio_vsock_sock {
> struct list_head rx_queue;
> };
>
> +struct virtio_vsock_mrg_rxbuf {
> + void *buf;
> + u32 len;
> +};
> +
> struct virtio_vsock_pkt {
> struct virtio_vsock_hdr hdr;
> struct virtio_vsock_mrg_rxbuf_hdr mrg_rxbuf_hdr;
> @@ -59,6 +66,8 @@ struct virtio_vsock_pkt {
> u32 len;
> u32 off;
> bool reply;
> + bool mergeable;
> + struct virtio_vsock_mrg_rxbuf mrg_rxbuf[VIRTIO_VSOCK_MAX_MRG_BUF_NUM];
> };
It's better to use iov here I think, and drop buf completely.
And this is better to be done in an independent patch.
>
> struct virtio_vsock_pkt_info {
> diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
> index 2040a9e..3557ad3 100644
> --- a/net/vmw_vsock/virtio_transport.c
> +++ b/net/vmw_vsock/virtio_transport.c
> @@ -359,11 +359,62 @@ static bool virtio_transport_more_replies(struct virtio_vsock *vsock)
> return val < virtqueue_get_vring_size(vq);
> }
>
> +static struct virtio_vsock_pkt *receive_mergeable(struct virtqueue *vq,
> + struct virtio_vsock *vsock, unsigned int *total_len)
> +{
> + struct virtio_vsock_pkt *pkt;
> + u16 num_buf;
> + void *page;
> + unsigned int len;
> + int i = 0;
> +
> + page = virtqueue_get_buf(vq, &len);
> + if (!page)
> + return NULL;
> +
> + *total_len = len;
> + vsock->rx_buf_nr--;
> +
> + pkt = page;
> + num_buf = le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers);
> + if (!num_buf || num_buf > VIRTIO_VSOCK_MAX_MRG_BUF_NUM)
> + goto err;
> +
> + pkt->mergeable = true;
> + if (!le32_to_cpu(pkt->hdr.len))
> + return pkt;
> +
> + len -= sizeof(struct virtio_vsock_pkt);
> + pkt->mrg_rxbuf[i].buf = page + sizeof(struct virtio_vsock_pkt);
> + pkt->mrg_rxbuf[i].len = len;
> + i++;
> +
> + while (--num_buf) {
> + page = virtqueue_get_buf(vq, &len);
> + if (!page)
> + goto err;
> +
> + *total_len += len;
> + vsock->rx_buf_nr--;
> +
> + pkt->mrg_rxbuf[i].buf = page;
> + pkt->mrg_rxbuf[i].len = len;
> + i++;
> + }
> +
> + return pkt;
> +err:
> + virtio_transport_free_pkt(pkt);
> + return NULL;
> +}
Similar logic could be found at virtio-net driver.
Haven't thought this deeply, but it looks to me use virtio-net driver is
also possible, e.g for data-path, just register vsock specific callbacks.
> +
> static void virtio_transport_rx_work(struct work_struct *work)
> {
> struct virtio_vsock *vsock =
> container_of(work, struct virtio_vsock, rx_work);
> struct virtqueue *vq;
> + size_t vsock_hlen = vsock->mergeable ? sizeof(struct virtio_vsock_pkt) :
> + sizeof(struct virtio_vsock_hdr);
>
> vq = vsock->vqs[VSOCK_VQ_RX];
>
> @@ -383,21 +434,29 @@ static void virtio_transport_rx_work(struct work_struct *work)
> goto out;
> }
>
> - pkt = virtqueue_get_buf(vq, &len);
> - if (!pkt) {
> - break;
> - }
> + if (likely(vsock->mergeable)) {
> + pkt = receive_mergeable(vq, vsock, &len);
> + if (!pkt)
> + break;
>
> - vsock->rx_buf_nr--;
> + pkt->len = le32_to_cpu(pkt->hdr.len);
> + } else {
> + pkt = virtqueue_get_buf(vq, &len);
> + if (!pkt) {
> + break;
> + }
> +
> + vsock->rx_buf_nr--;
> + }
>
> /* Drop short/long packets */
> - if (unlikely(len < sizeof(pkt->hdr) ||
> - len > sizeof(pkt->hdr) + pkt->len)) {
> + if (unlikely(len < vsock_hlen ||
> + len > vsock_hlen + pkt->len)) {
> virtio_transport_free_pkt(pkt);
> continue;
> }
>
> - pkt->len = len - sizeof(pkt->hdr);
> + pkt->len = len - vsock_hlen;
> virtio_transport_deliver_tap_pkt(pkt);
> virtio_transport_recv_pkt(pkt);
> }
> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c
> index 3ae3a33..7bef1d5 100644
> --- a/net/vmw_vsock/virtio_transport_common.c
> +++ b/net/vmw_vsock/virtio_transport_common.c
> @@ -272,14 +272,49 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk,
> */
> spin_unlock_bh(&vvs->rx_lock);
>
> - err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
> - if (err)
> - goto out;
> + if (pkt->mergeable) {
> + struct virtio_vsock_mrg_rxbuf *buf = pkt->mrg_rxbuf;
> + size_t mrg_copy_bytes, last_buf_total = 0, rxbuf_off;
> + size_t tmp_bytes = bytes;
> + int i;
> +
> + for (i = 0; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) {
> + if (pkt->off > last_buf_total + buf[i].len) {
> + last_buf_total += buf[i].len;
> + continue;
> + }
> +
> + rxbuf_off = pkt->off - last_buf_total;
> + mrg_copy_bytes = min(buf[i].len - rxbuf_off, tmp_bytes);
> + err = memcpy_to_msg(msg, buf[i].buf + rxbuf_off, mrg_copy_bytes);
> + if (err)
> + goto out;
> +
> + tmp_bytes -= mrg_copy_bytes;
> + pkt->off += mrg_copy_bytes;
> + last_buf_total += buf[i].len;
> + if (!tmp_bytes)
> + break;
> + }
After switch to use iov, you can user iov_iter helper to avoid the above
open-coding I believe.
And you can also drop the if (mergeable) condition.
Thanks
> +
> + if (tmp_bytes) {
> + printk(KERN_WARNING "WARNING! bytes = %llu, "
> + "bytes = %llu\n",
> + (unsigned long long)bytes,
> + (unsigned long long)tmp_bytes);
> + }
> +
> + total += (bytes - tmp_bytes);
> + } else {
> + err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
> + if (err)
> + goto out;
> +
> + total += bytes;
> + pkt->off += bytes;
> + }
>
> spin_lock_bh(&vvs->rx_lock);
> -
> - total += bytes;
> - pkt->off += bytes;
> if (pkt->off == pkt->len) {
> virtio_transport_dec_rx_pkt(vvs, pkt);
> list_del(&pkt->list);
> @@ -1050,8 +1085,16 @@ void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt)
>
> void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt)
> {
> - kfree(pkt->buf);
> - kfree(pkt);
> + int i;
> +
> + if (pkt->mergeable) {
> + for (i = 1; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++)
> + free_page((unsigned long)pkt->mrg_rxbuf[i].buf);
> + free_page((unsigned long)(void *)pkt);
> + } else {
> + kfree(pkt->buf);
> + kfree(pkt);
> + }
> }
> EXPORT_SYMBOL_GPL(virtio_transport_free_pkt);
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Rules for retransmitting sk_buffs?
From: John Ousterhout @ 2018-11-05 18:34 UTC (permalink / raw)
To: netdev
I am creating a kernel module that implements the Homa transport
protocol (see paper in SIGCOMM 2018) and as a Linux kernel newbie I'm
struggling a bit to figure out how all of Linux's network plumbing
works.
I'm currently having problems retransmitting an sk_buff after packet
loss and hoping that perhaps someone here can help me understand the
rules and/or constraints around retransmission. Pointers to any
existing documentation would also be great.
I'm currently using the naive approach: Homa saves a reference to the
sk_buff after it is first transmitted, and if retransmission is
necessary it calls ip_queue_xmit again with the same sk_buff (it also
reuses the same flowi and dst as in the first call). The behavior I'm
seeing is very strange: the second call to ip_queue_xmit is modifying
the flowi so that its daddr is 127.0.0.1. This then results in an
ICMP_DEST_UNREACH error.
Am I doing something fundamentally wrong here? E.g., do I need to
clone the sk_buff before retransmitting it? If so, are there any
restrictions on *when* I clone it (I'd prefer not to do this unless
retransmission is necessary, just to save work).
Thanks in advance for any advice/pointers.
-John-
^ permalink raw reply
* Re: [PATCH] sock_diag: fix autoloading of the raw_diag module
From: Cyrill Gorcunov @ 2018-11-05 18:22 UTC (permalink / raw)
To: Andrei Vagin; +Cc: David S. Miller, netdev, Xin Long
In-Reply-To: <20181105071234.GC2869@uranus.lan>
On Mon, Nov 05, 2018 at 10:12:34AM +0300, Cyrill Gorcunov wrote:
>
> Andrew, looking into kernel code I wonder, maybe we should simply
> add this protocol into inet_protos during net/ipv4/af_inet.c:inet_init?
> It will require to add netns_ok into raw_prot of course.
After spending some time on this idea I think your patch is better,
since it is small and suitable for a -stable fix (because the former
issue is definitely changing the kernel behaviour, the fix should
be passed to -stable as well).
Reviewed-by: Cyrill Gorcunov <gorcunov@gmail.com>
^ permalink raw reply
* Re: [PATCH 0/5] VSOCK: support mergeable rx buffer in vhost-vsock
From: jiangyiwen @ 2018-11-06 3:17 UTC (permalink / raw)
To: Jason Wang, stefanha; +Cc: netdev, kvm, virtualization
In-Reply-To: <b4ce06c8-1c4b-724f-52e8-cb8d7b23fd27@redhat.com>
On 2018/11/6 10:41, Jason Wang wrote:
>
> On 2018/11/6 上午10:17, jiangyiwen wrote:
>> On 2018/11/5 17:21, Jason Wang wrote:
>>> On 2018/11/5 下午3:43, jiangyiwen wrote:
>>>> Now vsock only support send/receive small packet, it can't achieve
>>>> high performance. As previous discussed with Jason Wang, I revisit the
>>>> idea of vhost-net about mergeable rx buffer and implement the mergeable
>>>> rx buffer in vhost-vsock, it can allow big packet to be scattered in
>>>> into different buffers and improve performance obviously.
>>>>
>>>> I write a tool to test the vhost-vsock performance, mainly send big
>>>> packet(64K) included guest->Host and Host->Guest. The result as
>>>> follows:
>>>>
>>>> Before performance:
>>>> Single socket Multiple sockets(Max Bandwidth)
>>>> Guest->Host ~400MB/s ~480MB/s
>>>> Host->Guest ~1450MB/s ~1600MB/s
>>>>
>>>> After performance:
>>>> Single socket Multiple sockets(Max Bandwidth)
>>>> Guest->Host ~1700MB/s ~2900MB/s
>>>> Host->Guest ~1700MB/s ~2900MB/s
>>>>
>>>> From the test results, the performance is improved obviously, and guest
>>>> memory will not be wasted.
>>> Hi:
>>>
>>> Thanks for the patches and the numbers are really impressive.
>>>
>>> But instead of duplicating codes between sock and net. I was considering to use virtio-net as a transport of vsock. Then we may have all existed features likes batching, mergeable rx buffers and multiqueue. Want to consider this idea? Thoughts?
>>>
>>>
>> Hi Jason,
>>
>> I am not very familiar with virtio-net, so I am afraid I can't give too
>> much effective advice. Then I have several problems:
>>
>> 1. If use virtio-net as a transport, guest should see a virtio-net
>> device instead of virtio-vsock device, right? Is vsock only as a
>> transport between socket and net_device? User should still use
>> AF_VSOCK type to create socket, right?
>
>
> Well, there're many choices. What you need is just to keep the socket API and hide the implementation. For example, you can keep the vosck device in guest and switch to use vhost-net in host. We probably need a new feature bit or header to let vhost know we are passing vsock packet. And vhost-net could forward the packet to vsock core on host.
>
>
>>
>> 2. I want to know if this idea has already started, and how is
>> the current progress?
>
>
> Not yet started. Just want to listen from the community. If this sounds good, do you have interest in implementing this?
>
>
>>
>> 3. And what is stefan's idea?
>
>
> Talk with Stefan a little on this during KVM Forum. I think he tends to agree on this idea. Anyway, let's wait for his reply.
>
>
> Thanks
>
>
Hi Jason,
Thanks your reply, what you want is try to avoid duplicate code, and still
use the existed features with virtio-net.
Yes, if this sounds good and most people can recognize this idea, I am very
happy to implement this.
In addition, I hope you can review these patches before the new idea is
implemented, after all the performance can be improved. :-)
Thanks,
Yiwen.
>>
>> Thanks,
>> Yiwen.
>>
>
> .
>
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
^ permalink raw reply
* Re: [PATCH 1/1] vhost: add per-vq worker thread
From: Vitaly Mayatskih @ 2018-11-06 2:59 UTC (permalink / raw)
To: Jason Wang; +Cc: Michael S . Tsirkin, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <617e0c54-7d11-09b6-21e5-968260107872@redhat.com>
On Mon, Nov 5, 2018 at 9:49 PM Jason Wang <jasowang@redhat.com> wrote:
> If you allow device to specify the worker itself, you can do any kinds
> of mapping bettween work and worker kthread I think. The advantage of
> doing this is that you can keep the vhost-net untouched. This makes
> things a little bit easier and proving two kthreads is better than one
> for -net workload is probably not as easy as it looks. We may get boost
> in some cases but degradation for the rest.
Sounds good. 1 worker is created by vhost as today, all the others are
entering from userspace via ioctl.
--
wbr, Vitaly
^ permalink raw reply
* Re: [PATCH 1/1] vhost: add per-vq worker thread
From: Jason Wang @ 2018-11-06 2:48 UTC (permalink / raw)
To: Vitaly Mayatskih
Cc: Michael S . Tsirkin, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <CAGF4SLgDk+48aLKHhA_ZgRc6D30tGdnB89b5m5bZKwzyoDb0dQ@mail.gmail.com>
On 2018/11/5 上午11:28, Vitaly Mayatskih wrote:
> On Sun, Nov 4, 2018 at 9:53 PM Jason Wang <jasowang@redhat.com> wrote:
>
>> I wonder whether or not it's better to allow the device to specific the
>> worker here instead of forcing a per vq worker model. Then we can keep
>> the behavior of exist implementation and do optimization on top?
> I was thinking about that too, but for the sake of simplicity it
> sounds valid that if the user wanted 8 parallel queues for the disk,
> they better be parallel, i.e. worker per queue. The rest of disks that
> don't need high-performance, can have 1 queue specified.
>
If you allow device to specify the worker itself, you can do any kinds
of mapping bettween work and worker kthread I think. The advantage of
doing this is that you can keep the vhost-net untouched. This makes
things a little bit easier and proving two kthreads is better than one
for -net workload is probably not as easy as it looks. We may get boost
in some cases but degradation for the rest.
Thanks
^ permalink raw reply
* [PATCH V2 6/7] net: maclorawan: Implement maclorawan class module
From: Jian-Hong Pan @ 2018-11-05 16:55 UTC (permalink / raw)
To: Andreas Färber
Cc: netdev, linux-arm-kernel, linux-kernel, Marcel Holtmann,
David S . Miller, Dollar Chen, Ken Yu, linux-wpan, Stefan Schmidt,
Jian-Hong Pan
In-Reply-To: <fc737f3940bbe91341fb15d85ac11931eb56d1fc.1535039998.git.starnight@g.ncu.edu.tw>
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
net/maclorawan/Kconfig | 14 +
net/maclorawan/Makefile | 2 +
net/maclorawan/mac.c | 522 ++++++++++++++++++++++++++++++++++
net/maclorawan/main.c | 600 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 1138 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..343fe729a883
--- /dev/null
+++ b/net/maclorawan/mac.c
@@ -0,0 +1,522 @@
+/* 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;
+ __le32 le_devaddr = cpu_to_le32(ss->devaddr);
+ u8 mhdr, fctrl, fport;
+ u8 mic[4];
+
+ netdev_dbg(lrw_st->ndev, "%s\n", __func__);
+
+ mhdr = LRW_UNCONFIRMED_DATA_UP << 5;
+ if ((mhdr & (0x6 << 5)) == (0x4 << 5))
+ ss->tx_should_ack = true;
+
+ fctrl = 0;
+ if (lrw_st->rx_should_ack) {
+ fctrl |= 0x20;
+ lrw_st->rx_should_ack = false;
+ }
+
+ /* 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 */
+ memcpy(skb_push(skb, 2), &ss->fcnt_up, 2);
+
+ /* Push FCtrl */
+ memcpy(skb_push(skb, 1), &fctrl, 1);
+
+ /* Push DevAddr */
+ memcpy(skb_push(skb, LRW_DEVADDR_LEN), &le_devaddr, LRW_DEVADDR_LEN);
+
+ /* Push MHDR */
+ 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;
+ u16 fcnt;
+ __le16 *p_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);
+
+ 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)
+{
+ u8 *buf;
+ size_t len;
+ u32 devaddr;
+ u16 fcnt;
+ __le16 *p_fcnt;
+ u8 cks[4];
+ u8 *mic;
+
+ buf = skb->data;
+ len = skb->len - 4;
+ devaddr = le32_to_cpu(*((__le32 *)(buf + 1)));
+ p_fcnt = (__le16 *)(buf + 6);
+ fcnt = le16_to_cpu(*p_fcnt);
+ 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);
+ u8 mtype;
+ u32 devaddr;
+
+ 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_session *ss;
+ struct lrw_struct *lrw_st;
+
+ 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..002781295369
--- /dev/null
+++ b/net/maclorawan/main.c
@@ -0,0 +1,600 @@
+/* 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 net_device *ndev;
+ struct lrw_struct *lrw_st;
+ 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
+ */
+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
+ */
+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)
+{
+ bool status = false;
+ struct lrw_session *ss;
+
+ 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;
+}
+
+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 = 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;
+}
+
+inline 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;
+}
+
+inline 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;
+}
+
+inline 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 = (__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);
+
+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);
+
+ pr_info("%s: unregister %s\n",
+ LORAWAN_MODULE_NAME, dev_name(&lrw_st->dev));
+
+ /* 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
* [PATCH V2 4/7] net: maclorawan: Add maclorawan module declaration
From: Jian-Hong Pan @ 2018-11-05 16:55 UTC (permalink / raw)
To: Andreas Färber
Cc: netdev, linux-arm-kernel, linux-kernel, Marcel Holtmann,
David S . Miller, Dollar Chen, Ken Yu, linux-wpan, Stefan Schmidt,
Jian-Hong Pan
In-Reply-To: <fc737f3940bbe91341fb15d85ac11931eb56d1fc.1535039998.git.starnight@g.ncu.edu.tw>
Add the maclorawan header file for common APIs in the module.
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
- Use SPDX license identifiers
net/maclorawan/maclorawan.h | 199 ++++++++++++++++++++++++++++++++++++
1 file changed, 199 insertions(+)
create mode 100644 net/maclorawan/maclorawan.h
diff --git a/net/maclorawan/maclorawan.h b/net/maclorawan/maclorawan.h
new file mode 100644
index 000000000000..66b87f051d51
--- /dev/null
+++ b/net/maclorawan/maclorawan.h
@@ -0,0 +1,199 @@
+/* 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>
+ *
+ */
+
+#ifndef __MAC_LORAWAN_H__
+#define __MAC_LORAWAN_H__
+
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/netdevice.h>
+#include <uapi/linux/if_arp.h>
+#include <crypto/hash.h>
+#include <crypto/skcipher.h>
+#include <linux/lora/lorawan.h>
+
+#define LORAWAN_MODULE_NAME "maclorawan"
+
+/* List the message types of LoRaWAN */
+enum {
+ LRW_JOIN_REQUEST,
+ LRW_JOIN_ACCEPT,
+ LRW_UNCONFIRMED_DATA_UP,
+ LRW_UNCONFIRMED_DATA_DOWN,
+ LRW_CONFIRMED_DATA_UP,
+ LRW_CONFIRMED_DATA_DOWN,
+ LRW_RFU,
+ LRW_PROPRIETARY,
+};
+
+/* List the communication directions */
+enum {
+ LRW_UPLINK,
+ LRW_DOWNLINK,
+};
+
+/* States of LoRaWAN slot timing */
+enum {
+ LRW_INIT_SS,
+ LRW_XMITTING_SS,
+ LRW_XMITTED,
+ LRW_RX1_SS,
+ LRW_RX2_SS,
+ LRW_RXTIMEOUT_SS,
+ LRW_RXRECEIVED_SS,
+ LRW_RETRANSMIT_SS,
+};
+
+#define LRW_MHDR_LEN 1
+#define LRW_FHDR_MAX_LEN 22
+#define LRW_FOPS_MAX_LEN 15
+#define LRW_FPORT_LEN 1
+#define LRW_MIC_LEN 4
+
+/**
+ * lrw_fhdr - Hold the message's basic information of the frame
+ *
+ * @mtype: this message's type
+ * @fctrl: the frame control byte
+ * @fcnt: this message's frame counter value
+ * @fopts: this frame's options field
+ * @fopts_len: the length of the fopts
+ */
+struct lrw_fhdr {
+ u8 mtype;
+ u8 fctrl;
+ u16 fcnt;
+ u8 fopts[LRW_FPORT_LEN];
+ u8 fopts_len;
+};
+
+/**
+ * lrw_session - LoRaWAN session for Class A end device
+ *
+ * @lrw_st: points to the belonging lrw_st
+ * @entry: the entry of the ss_list in lrw_struct
+ * @devaddr: the LoRaWAN device address of this LoRaWAN hardware
+ * @fcnt_up: uplink frame counter
+ * @fcnt_down: downlink frame counter
+ * @fport: the LoRaWAN data message's port field
+ * @tx_skb: points to the TX skb, the frame
+ * @rx_skb: points to the RX skb, the frame
+ * @tx_fhdr: hold the message's basic information of the TX frame
+ * @rx_fhdr: hold the message's basic information of the RX frame
+ * @tx_should_ack: flag for determining the TX which should be acked or not
+ * @retry: retry times for xmitting failed
+ * @state: this session's current state
+ * @state_lock: lock of the session's state
+ * @timer: timing for this session and the state transition
+ * @timeout_work: work if waiting acknowledge time out
+ * @rx_delay1: RX1 delay time in seconds
+ * @rx_delay2: RX2 delay time in seconds
+ * @rx1_window: RX1 window opening time in mini-seconds
+ * @rx2_window: RX2 window opening time in mini-seconds
+ * @ack_timeout: time out time for waiting acknowledge in seconds
+ */
+struct lrw_session {
+ struct lrw_struct *lrw_st;
+ struct list_head entry;
+
+ u32 devaddr;
+ u16 fcnt_up;
+ u16 fcnt_down;
+ u8 fport;
+ struct sk_buff *tx_skb;
+ struct sk_buff *rx_skb;
+ struct lrw_fhdr tx_fhdr;
+ struct lrw_fhdr rx_fhdr;
+
+ bool tx_should_ack;
+ u8 retry;
+ u8 state;
+ spinlock_t state_lock;
+
+ struct timer_list timer;
+ struct work_struct timeout_work;
+ unsigned long rx_delay1;
+ unsigned long rx_delay2;
+ unsigned long rx1_window;
+ unsigned long rx2_window;
+ unsigned long ack_timeout;
+};
+
+/**
+ * lrw_struct - The full LoRaWAN hardware to the LoRa device.
+ *
+ * @dev: this LoRa device registed in system
+ * @hw: the LoRa device of this LoRaWAN hardware
+ * @ops: handle of LoRa operations interfaces
+ * @rx_skb_list: the list of received frames
+ * @ss_list: LoRaWAN session list of this LoRaWAN hardware
+ * @_cur_ss: pointer of the current processing session
+ * @rx_should_ack: represent the current session should be acked or not
+ * @state: the state of this LoRaWAN hardware
+ * @app_eui: the LoRaWAN application EUI
+ * @dev_eui: the LoRaWAN device EUI
+ * @devaddr: the LoRaWAN device address of this LoRaWAN hardware
+ * @appky: the Application key
+ * @nwkskey: the Network session key
+ * @appskey: the Application session key
+ * @nwks_shash_tfm: the hash handler for LoRaWAN network session
+ * @nwks_skc_tfm: the crypto handler for LoRaWAN network session
+ * @apps_skc_tfm: the crypto handler for LoRaWAN application session
+ * @fcnt_up: the counter of this LoRaWAN hardware's up frame
+ * @fcnt_down: the counter of this LoRaWAN hardware's down frame
+ * @xmit_task: the xmit task for the current LoRaWAN session
+ * @rx_work: the RX work in workqueue for the current LoRaWAN session
+ * @ndev: points to the emulating network device
+ * @_net: the current network namespace of this LoRaWAN hardware
+ */
+struct lrw_struct {
+ struct device dev;
+ struct lrw_hw hw;
+ struct lrw_operations *ops;
+
+ struct sk_buff_head rx_skb_list;
+ struct list_head ss_list;
+ struct mutex ss_list_lock;
+ struct lrw_session *_cur_ss;
+ bool rx_should_ack;
+ u8 state;
+
+ u64 app_eui;
+ u64 dev_eui;
+ u32 devaddr;
+ u8 appkey[LRW_KEY_LEN];
+ u8 nwkskey[LRW_KEY_LEN];
+ u8 appskey[LRW_KEY_LEN];
+ struct crypto_shash *nwks_shash_tfm;
+ struct crypto_skcipher *nwks_skc_tfm;
+ struct crypto_skcipher *apps_skc_tfm;
+
+ u16 fcnt_up;
+ u16 fcnt_down;
+
+ struct tasklet_struct xmit_task;
+ struct work_struct rx_work;
+
+ struct net_device *ndev;
+ possible_net_t _net;
+};
+
+#define NETDEV_2_LRW(ndev) ((struct lrw_struct *)netdev_priv(ndev))
+
+struct lrw_session * lrw_alloc_ss(struct lrw_struct *);
+void lrw_free_ss(struct lrw_session *);
+void lrw_del_ss(struct lrw_session *);
+int lrw_start_hw(struct lrw_struct *);
+void lrw_stop_hw(struct lrw_struct *);
+void lrw_prepare_tx_frame(struct lrw_session *);
+void lrw_xmit(unsigned long);
+void lrw_rx_work(struct work_struct *);
+
+#endif
--
2.19.1
^ permalink raw reply related
* [PATCH V2 3/7] net: lorawan: Add LoRaWAN API declaration for LoRa devices
From: Jian-Hong Pan @ 2018-11-05 16:55 UTC (permalink / raw)
To: Andreas Färber
Cc: netdev, linux-arm-kernel, linux-kernel, Marcel Holtmann,
David S . Miller, Dollar Chen, Ken Yu, linux-wpan, Stefan Schmidt,
Jian-Hong Pan
In-Reply-To: <fc737f3940bbe91341fb15d85ac11931eb56d1fc.1535039998.git.starnight@g.ncu.edu.tw>
Add public LoRaWAN API 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
- Merge the lrw_operations: set_bw, set_mod, set_sf into set_dr
- Use SPDX license identifiers
include/linux/lora/lorawan.h | 137 +++++++++++++++++++++++++++++++++++
1 file changed, 137 insertions(+)
create mode 100644 include/linux/lora/lorawan.h
diff --git a/include/linux/lora/lorawan.h b/include/linux/lora/lorawan.h
new file mode 100644
index 000000000000..684c9e2eb018
--- /dev/null
+++ b/include/linux/lora/lorawan.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */
+/*-
+ * LoRaWAN compatible hardware's definitions
+ *
+ * Copyright (c) 2018 Jian-Hong, Pan <starnight@g.ncu.edu.tw>
+ *
+ */
+
+#ifndef __LORAWAN_H__
+#define __LORAWAN_H__
+
+#include <linux/skbuff.h>
+#include <linux/random.h>
+
+/* List the role of the LoRaWAN hardware */
+enum {
+ LRW_GATEWAY,
+ LRW_CLASS_A_NODE,
+ LRW_CLASS_B_NODE,
+ LRW_CLASS_C_NODE,
+};
+
+/* List the RF modes */
+enum {
+ LRW_LORA,
+ LRW_FSK,
+};
+
+/**
+ * lrw_dr - This structure holds the RF related configuration of the data rate.
+ * @bw:
+ * Bandwidth in Hz
+ *
+ * @sf:
+ * Spread factor of CSS modulation used by LoRa mode
+ *
+ * @mode:
+ * LoRa or FSK mode
+ */
+struct lrw_dr {
+ u32 bw;
+ u8 sf;
+ u8 mode;
+};
+
+#define LRW_DEVADDR_LEN (sizeof(__le32))
+
+/* List the LoRa device's states of LoRaWAN hardware */
+enum {
+ LRW_STOP,
+ LRW_START,
+ LRW_STATE_IDLE,
+ LRW_STATE_TX,
+ LRW_STATE_RX,
+};
+
+/**
+ * lrw_hw - This structure holds the LoRa device of LoRaWAN hardware.
+ * @priv:
+ * points to the private data of the LoRa device
+ */
+struct lrw_hw {
+ void *priv;
+};
+
+/**
+ * lrw_operations - Lists the LoRaWAN device/interface's operations.
+ * These are callback functions for the LoRaWAN module. Compatible LoRa device
+ * driver should implement some of them according to the usage. The
+ * unimplemented callback functions must be assigned as NULL.
+ *
+ * @start:
+ * called when the interface is being up state
+ *
+ * @stop:
+ * called when the interface is being down state
+ *
+ * @xmit_async:
+ * called to xmit the data through the interface asynchronously
+ *
+ * @set_txpower:
+ * called to set xmitting RF power in mBm of the interface
+ *
+ * @set_frq:
+ * called to set carrier frequency in Hz of the interface
+ *
+ * @set_dr:
+ * called to set related RF configuration of the LoRaWAN data rate
+ *
+ * @start_rx_window:
+ * called to ask the LoRa device open a receiving window
+ *
+ * @set_state:
+ * called to set the LoRa device's working state
+ */
+struct lrw_operations {
+ int (*start)(struct lrw_hw *);
+ void (*stop)(struct lrw_hw *);
+
+ int (*xmit_async)(struct lrw_hw *, struct sk_buff *);
+ int (*set_txpower)(struct lrw_hw *, s32);
+ int (*set_frq)(struct lrw_hw *, u32);
+ int (*set_dr)(struct lrw_hw *, struct lrw_dr *);
+ int (*start_rx_window)(struct lrw_hw *, u32);
+ int (*set_state)(struct lrw_hw *, u8);
+};
+
+struct lrw_hw *lrw_alloc_hw(size_t, struct lrw_operations *);
+void lrw_free_hw(struct lrw_hw *);
+int lrw_register_hw(struct lrw_hw *);
+void lrw_unregister_hw(struct lrw_hw *);
+void lrw_rx_irqsave(struct lrw_hw *, struct sk_buff *);
+void lrw_xmit_complete(struct lrw_hw *, struct sk_buff *);
+
+static inline void lrw_random_addr(u64 *addr)
+{
+ get_random_bytes(addr, sizeof(u64));
+}
+
+void lrw_set_deveui(struct lrw_hw *, u64);
+u64 lrw_get_deveui(struct lrw_hw *);
+void lrw_set_appeui(struct lrw_hw *, u64);
+u64 lrw_get_appeui(struct lrw_hw *);
+void lrw_set_devaddr(struct lrw_hw *, u32);
+u32 lrw_get_devaddr(struct lrw_hw *);
+
+enum {
+ LRW_APPKEY,
+ LRW_NWKSKEY,
+ LRW_APPSKEY,
+};
+
+#define LRW_KEY_LEN 16
+
+int lrw_set_key(struct lrw_hw *, u8, u8 *, size_t);
+
+#endif
--
2.19.1
^ permalink raw reply related
* [lora-next RFC] Socket details for PF_LORA on sx1301
From: Ben Whitten @ 2018-11-05 16:45 UTC (permalink / raw)
To: afaerber@suse.de
Cc: starnight@g.ncu.edu.tw, hasnain.virk@arm.com,
netdev@vger.kernel.org, liuxuenetmail@gmail.com,
shess@hessware.de
Hi,
Using the test application to send data into a PF_LORA socket I have gotten
the sx1301 driver to a point where I was able to produce a LoRa packet
on the air.
There a few options that this socket will need per transmission from the
upper layers which I have compiled with some questions, I will focus on
the LoRa modulation - will FSK have a different socket type?
Transmission frequency in MHz.
Transmit time - can we use SO_TXTIME sockopt?
Modulation bandwidth.
Transmission power in dBm.
Enable CRC16.
Coding rate.
Spreading factor.
Preamble.
The rest of the info needed to program the sx1301 can be inferred from
the hardware configuration or set as a sysfs entry if needed; for example
which radio (A/B) to use as transmitter.
The reference design only has one radios (A) transmit pins connected so
is a static hardware choice set in DTS.
What would be the best way to get this additional info down to the lora
portion of the socket, setsockopts?
Thanks,
Ben Whitten
^ permalink raw reply
* Re: [PATCH iproute2-next] rdma: Refresh help section of resource information
From: Stephen Hemminger @ 2018-11-05 16:40 UTC (permalink / raw)
To: Leon Romanovsky
Cc: David Ahern, Leon Romanovsky, netdev, RDMA mailing list,
Steve Wise
In-Reply-To: <20181101083505.25152-1-leon@kernel.org>
On Thu, 1 Nov 2018 10:35:05 +0200
Leon Romanovsky <leon@kernel.org> wrote:
> From: Leon Romanovsky <leonro@mellanox.com>
>
> After commit 4060e4c0d257 ("rdma: Add PD resource tracking
> information"), the resource information shows PDs and MRs,
> but help pages didn't fully reflect it.
>
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
Applied
^ permalink raw reply
* Re: [PATCH iproute2] Include bsd/string.h only in include/utils.h
From: Stephen Hemminger @ 2018-11-05 16:39 UTC (permalink / raw)
To: Luca Boccassi; +Cc: netdev, dsahern
In-Reply-To: <20181101222527.29439-1-bluca@debian.org>
On Thu, 1 Nov 2018 22:25:27 +0000
Luca Boccassi <bluca@debian.org> wrote:
> This is simpler and cleaner, and avoids having to include the header
> from every file where the functions are used. The prototypes of the
> internal implementation are in this header, so utils.h will have to be
> included anyway for those.
>
> Fixes: 508f3c231efb ("Use libbsd for strlcpy if available")
>
> Signed-off-by: Luca Boccassi <bluca@debian.org>
Looks better. Applied
^ permalink raw reply
* [GIT] Networking
From: David Miller @ 2018-11-06 1:42 UTC (permalink / raw)
To: torvalds; +Cc: akpm, netdev, linux-kernel
1) Handle errors mid-stream of an all dump, from Alexey Kodanev.
2) Fix build of openvswitch with certain combinations of netfilter
options, from Arnd Bergmann.
3) Fix interactions between GSO and BQL, from Eric Dumazet.
4) Don't put a '/' in RTL8201F's sysfs file name, from Holger
Hoffstätte.
5) S390 qeth driver fixes from Julian Wiedmann.
6) Allow ipv6 link local addresses for netconsole when both source
and destination are link local, from Matwey V. Kornilov.
7) Fix the BPF program address seen in /proc/kallsyms, from Song Liu.
8) Initialize mutex before use in dsa microchip driver, from Tristram
Ha.
9) Out-of-bounds access in hns3, from Yunsheng Lin.
10) Various netfilter fixes from Stefano Brivio, Jozsef Kadlecsik,
Jiri Slaby, Florian Westphal, Eric Westbrook, Andrey Ryabinin, and
Pablo Neira Ayuso.
Please pull, thanks!
The following changes since commit 7c6c54b505b8aea1782ce6a6e8f3b8297d179937:
Merge branch 'i2c/for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux (2018-11-01 09:31:19 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
for you to fetch changes up to a422757e8c323ae12163fa74bc21c41606a233df:
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf (2018-11-05 17:19:25 -0800)
----------------------------------------------------------------
Alexey Kodanev (2):
rtnetlink: restore handling of dumpit return value in rtnl_dump_all()
ipv6: properly check return value in inet6_dump_all()
Andrei Vagin (1):
sock_diag: fix autoloading of the raw_diag module
Andrey Ryabinin (1):
netfilter: ipset: fix ip_set_list allocation failure
Arnd Bergmann (2):
qed: fix link config error handling
openvswitch: fix linking without CONFIG_NF_CONNTRACK_LABELS
Cong Wang (1):
net: drop skb on failure in ip_check_defrag()
Daniel Borkmann (2):
Merge branch 'bpf-accurate-prog-addr'
bpf: fix bpf_prog_get_info_by_fd to return 0 func_lens for unpriv
David Howells (1):
rxrpc: Fix lockup due to no error backoff after ack transmit error
David S. Miller (5):
Merge branch 'net-timeout-fixes-for-GENET-and-SYSTEMPORT'
Merge branch 's390-qeth-fixes'
Merge branch 'net-bql-better-deal-with-GSO'
Merge git://git.kernel.org/.../bpf/bpf
Merge git://git.kernel.org/.../pablo/nf
Doug Berger (1):
net: bcmgenet: protect stop from timeout
Eric Dumazet (3):
net: bql: add __netdev_tx_sent_queue()
net: do not abort bulk send on BQL status
net/mlx4_en: use __netdev_tx_sent_queue()
Eric Westbrook (1):
netfilter: ipset: actually allow allowable CIDR 0 in hash:net,port,net
Florian Fainelli (1):
net: systemport: Protect stop from timeout
Florian Westphal (2):
netfilter: ipv6: fix oops when defragmenting locally generated fragments
netfilter: nft_compat: ebtables 'nat' table is normal chain type
Frieder Schrempf (1):
usbnet: smsc95xx: disable carrier check while suspending
Holger Hoffstätte (1):
net: phy: realtek: fix RTL8201F sysfs name
Jarod Wilson (1):
bonding/802.3ad: fix link_failure_count tracking
Jeff Barnhill (2):
net/ipv6: Add anycast addresses to a global hashtable
net/ipv6: Move anycast init/cleanup functions out of CONFIG_PROC_FS
Jiri Slaby (1):
netfilter: bridge: define INT_MIN & INT_MAX in userspace
Jozsef Kadlecsik (2):
netfilter: ipset: Correct rcu_dereference() call in ip_set_put_comment()
netfilter: ipset: Fix calling ip_set() macro at dumping
Julian Wiedmann (6):
s390/qeth: sanitize strings in debug messages
s390/qeth: fix HiperSockets sniffer
s390/qeth: unregister netdevice only when registered
s390/qeth: fix initial operstate
s390/qeth: sanitize ARP requests
s390/qeth: report 25Gbit link speed
Mathieu Malaterre (1):
net: document skb parameter in function 'skb_gso_size_check'
Matwey V. Kornilov (1):
net: core: netpoll: Enable netconsole IPv6 link local address
Pablo Neira Ayuso (4):
netfilter: nft_osf: check if attribute is present
Revert "netfilter: nft_numgen: add map lookups for numgen random operations"
netfilter: conntrack: add nf_{tcp,udp,sctp,icmp,dccp,icmpv6,generic}_pernet()
netfilter: nfnetlink_cttimeout: pass default timeout policy to obj_to_nlattr
Rasmus Villemoes (1):
net: alx: make alx_drv_name static
Shalom Toledo (1):
mlxsw: spectrum: Fix IP2ME CPU policer configuration
Song Liu (3):
bpf: show real jited prog address in /proc/kallsyms
bpf: show real jited address in bpf_prog_info->jited_ksyms
bpf: show main program address and length in bpf_prog_info
Stefano Brivio (1):
netfilter: ipset: list:set: Decrease refcount synchronously on deletion and replace
Taehee Yoo (2):
netfilter: xt_IDLETIMER: add sysfs filename checking routine
net: bpfilter: fix iptables failure if bpfilter_umh is disabled
Tristram Ha (1):
net: dsa: microchip: initialize mutex before use
Vasily Khoruzhick (1):
netfilter: conntrack: fix calculation of next bucket number in early_drop
Xin Long (2):
sctp: fix strchange_flags name for Stream Change Event
sctp: define SCTP_SS_DEFAULT for Stream schedulers
Yunsheng Lin (1):
net: hns3: Fix for out-of-bounds access when setting pfc back pressure
drivers/net/bonding/bond_main.c | 4 +-
drivers/net/dsa/microchip/ksz_common.c | 10 ++---
drivers/net/ethernet/atheros/alx/alx.h | 1 -
drivers/net/ethernet/atheros/alx/main.c | 2 +-
drivers/net/ethernet/broadcom/bcmsysport.c | 15 ++++----
drivers/net/ethernet/broadcom/genet/bcmgenet.c | 13 ++++---
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c | 10 ++---
drivers/net/ethernet/mellanox/mlx4/en_tx.c | 6 ++-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 -
drivers/net/ethernet/qlogic/qed/qed_mcp.c | 7 +++-
drivers/net/phy/realtek.c | 2 +-
drivers/net/usb/smsc95xx.c | 7 ++++
drivers/s390/net/qeth_core.h | 27 +++++++++----
drivers/s390/net/qeth_core_main.c | 172 ++++++++++++++++++++++++++++++++++++++++++++--------------------------------------
drivers/s390/net/qeth_core_mpc.h | 4 +-
drivers/s390/net/qeth_l2_main.c | 39 ++++++++++---------
drivers/s390/net/qeth_l3_main.c | 207 ++++++++++++++++++++++++++++++++++-----------------------------------------------------------------
include/linux/netdevice.h | 20 ++++++++++
include/linux/netfilter/ipset/ip_set.h | 2 +-
include/linux/netfilter/ipset/ip_set_comment.h | 4 +-
include/net/addrconf.h | 2 +
include/net/if_inet6.h | 2 +
include/net/netfilter/nf_conntrack_l4proto.h | 39 +++++++++++++++++++
include/uapi/linux/netfilter/nf_tables.h | 4 +-
include/uapi/linux/netfilter_bridge.h | 4 ++
include/uapi/linux/sctp.h | 3 ++
kernel/bpf/core.c | 4 +-
kernel/bpf/syscall.c | 35 ++++++++++++-----
net/core/dev.c | 2 +-
net/core/netpoll.c | 3 +-
net/core/rtnetlink.c | 2 +-
net/core/skbuff.c | 2 +
net/core/sock.c | 1 +
net/ipv4/ip_fragment.c | 12 ++++--
net/ipv4/ip_sockglue.c | 6 +--
net/ipv6/af_inet6.c | 5 +++
net/ipv6/anycast.c | 80 ++++++++++++++++++++++++++++++++++++--
net/ipv6/ip6_fib.c | 4 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 13 +++++--
net/netfilter/ipset/ip_set_core.c | 43 +++++++++++----------
net/netfilter/ipset/ip_set_hash_netportnet.c | 8 ++--
net/netfilter/ipset/ip_set_list_set.c | 17 ++++++---
net/netfilter/nf_conntrack_core.c | 13 ++++---
net/netfilter/nf_conntrack_proto_dccp.c | 13 ++-----
net/netfilter/nf_conntrack_proto_generic.c | 11 ++----
net/netfilter/nf_conntrack_proto_icmp.c | 11 ++----
net/netfilter/nf_conntrack_proto_icmpv6.c | 11 ++----
net/netfilter/nf_conntrack_proto_sctp.c | 11 ++----
net/netfilter/nf_conntrack_proto_tcp.c | 15 +++-----
net/netfilter/nf_conntrack_proto_udp.c | 11 ++----
net/netfilter/nfnetlink_cttimeout.c | 47 +++++++++++++++++++----
net/netfilter/nft_compat.c | 21 +++++-----
net/netfilter/nft_numgen.c | 127 -------------------------------------------------------------
net/netfilter/nft_osf.c | 2 +-
net/netfilter/xt_IDLETIMER.c | 20 ++++++++++
net/openvswitch/conntrack.c | 3 +-
net/rxrpc/ar-internal.h | 1 +
net/rxrpc/call_event.c | 18 +++++++--
net/rxrpc/output.c | 35 +++++++++++++++--
net/sctp/outqueue.c | 2 +-
60 files changed, 653 insertions(+), 563 deletions(-)
^ permalink raw reply
* Re: [PATCH] net: alx: make alx_drv_name static
From: David Miller @ 2018-11-06 1:13 UTC (permalink / raw)
To: linux; +Cc: jcliburn, chris.snook, netdev, linux-kernel
In-Reply-To: <20181105175222.12337-1-linux@rasmusvillemoes.dk>
From: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Date: Mon, 5 Nov 2018 18:52:21 +0100
> alx_drv_name is not used outside main.c, so there's no reason for it to
> have external linkage.
>
> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Applied.
^ permalink raw reply
* Re: [PATCH] net: core: netpoll: Enable netconsole IPv6 link local address
From: David Miller @ 2018-11-06 1:07 UTC (permalink / raw)
To: matwey
Cc: matwey.kornilov, edumazet, mingo, tglx, frederic, dbanerje, davej,
netdev, linux-kernel
In-Reply-To: <20181102181936.26294-1-matwey@sai.msu.ru>
From: "Matwey V. Kornilov" <matwey@sai.msu.ru>
Date: Fri, 2 Nov 2018 21:19:36 +0300
> There is no reason to discard using source link local address when
> remote netconsole IPv6 address is set to be link local one.
>
> The patch allows administrators to use IPv6 netconsole without
> explicitly configuring source address:
>
> netconsole=@/,@fe80::5054:ff:fe2f:6012/
>
> Signed-off-by: Matwey V. Kornilov <matwey@sai.msu.ru>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 5/6] net/ncsi: Reset channel state in ncsi_start_dev()
From: Samuel Mendoza-Jonas @ 2018-11-06 0:28 UTC (permalink / raw)
To: Justin.Lee1, netdev; +Cc: davem, linux-kernel, openbmc
In-Reply-To: <ea740068c02a47e2a5411f84c61e69b3@AUSX13MPS302.AMER.DELL.COM>
On Mon, 2018-11-05 at 18:01 +0000, Justin.Lee1@Dell.com wrote:
> > On Tue, 2018-10-30 at 21:26 +0000, Justin.Lee1@Dell.com wrote:
> > > > +int ncsi_reset_dev(struct ncsi_dev *nd)
> > > > +{
> > > > + struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
> > > > + struct ncsi_channel *nc, *active;
> > > > + struct ncsi_package *np;
> > > > + unsigned long flags;
> > > > + bool enabled;
> > > > + int state;
> > > > +
> > > > + active = NULL;
> > > > + NCSI_FOR_EACH_PACKAGE(ndp, np) {
> > > > + NCSI_FOR_EACH_CHANNEL(np, nc) {
> > > > + spin_lock_irqsave(&nc->lock, flags);
> > > > + enabled = nc->monitor.enabled;
> > > > + state = nc->state;
> > > > + spin_unlock_irqrestore(&nc->lock, flags);
> > > > +
> > > > + if (enabled)
> > > > + ncsi_stop_channel_monitor(nc);
> > > > + if (state == NCSI_CHANNEL_ACTIVE) {
> > > > + active = nc;
> > > > + break;
> > >
> > > Is the original intention to process the channel one by one?
> > > If it is the case, there are two loops and we might need to use
> > > "goto found" instead.
> >
> > Yes we'll need to break out of the package loop here as well.
> >
> > > > + }
> > > > + }
> > > > + }
> > > > +
> > >
> > > found: ?
> > >
> > > > + if (!active) {
> > > > + /* Done */
> > > > + spin_lock_irqsave(&ndp->lock, flags);
> > > > + ndp->flags &= ~NCSI_DEV_RESET;
> > > > + spin_unlock_irqrestore(&ndp->lock, flags);
> > > > + return ncsi_choose_active_channel(ndp);
> > > > + }
> > > > +
> > > > + spin_lock_irqsave(&ndp->lock, flags);
> > > > + ndp->flags |= NCSI_DEV_RESET;
> > > > + ndp->active_channel = active;
> > > > + ndp->active_package = active->package;
> > > > + spin_unlock_irqrestore(&ndp->lock, flags);
> > > > +
> > > > + nd->state = ncsi_dev_state_suspend;
> > > > + schedule_work(&ndp->work);
> > > > + return 0;
> > > > +}
> > >
> > > Also similar issue in ncsi_choose_active_channel() function below.
> > >
> > > > @@ -916,32 +1045,49 @@ static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp)
> > > >
> > > > ncm = &nc->modes[NCSI_MODE_LINK];
> > > > if (ncm->data[2] & 0x1) {
> > > > - spin_unlock_irqrestore(&nc->lock, flags);
> > > > found = nc;
> > > > - goto out;
> > > > + with_link = true;
> > > > }
> > > >
> > > > - spin_unlock_irqrestore(&nc->lock, flags);
> > > > + /* If multi_channel is enabled configure all valid
> > > > + * channels whether or not they currently have link
> > > > + * so they will have AENs enabled.
> > > > + */
> > > > + if (with_link || np->multi_channel) {
> > >
> > > I notice that there is a case that we will misconfigure the interface.
> > > For example below, multi-channel is not enable for package 1.
> > > But we enable the channel for ncsi2 below (package 1 channel 0) as that interface is the first
> > > channel for that package with link.
> >
> > I don't think I see the issue here; multi-channel is not set on package
> > 1, but both channels are in the channel whitelist. Channel 0 is
> > configured since it's the first found on package 1, and channel 1 is not
> > since channel 0 is already found. Are you expecting something different?
> >
>
> The setting is that multi-package is enable for both package 0 and 1.
> Multi-channel is only enabled for package 0.
>
> > > cat /sys/kernel/debug/ncsi_protocol/ncsi_device_
> > > IFIDX IFNAME NAME PID CID RX TX MP MC WP WC PC CS PS LS RU CR NQ HA
> > > =====================================================================
> > > 2 eth2 ncsi0 000 000 1 1 1 1 1 1 0 2 1 1 1 1 0 1
> > > 2 eth2 ncsi1 000 001 1 0 1 1 1 1 0 2 1 1 1 1 0 1
> > > 2 eth2 ncsi2 001 000 1 0 1 0 1 1 0 2 1 1 1 1 0 1
>
> I was replying to the wrong old email and it might cause a bit confusion.
> The first 1 meaning channel is enabled for package 1 channel 0 (ncsi2).
> For eth2, we already has ncsi0 as the active channel with TX enable.
> I would think that package doesn't have the multi-channel enabled and
> we should not enable the channel for ncsi2. The problem is that package 1 doesn't
> enable the multi-channel and it believes it needs to enable one channel for its package
> but it doesn't aware that the other package already has one active channel.
Ah, maybe the confusion here is that multi_channel is a per-package
setting; it determines what a package does with its own channels.
So you have package 0 with multi-channel enabled so it enables channels 0
& 1.
Then you have package 1 without multi-channel so it enables only channel
0.
There is still only one Tx channel (package 0, channel 0).
Does that sound right, or have I missed something?
>
> > > 2 eth2 ncsi3 001 001 0 0 1 0 1 1 0 1 0 1 1 1 0 1
> > > =====================================================================
> > > MP: Multi-mode Package WP: Whitelist Package
> > > MC: Multi-mode Channel WC: Whitelist Channel
> > > PC: Primary Channel CS: Channel State IA/A/IV 1/2/3
> > > PS: Poll Status LS: Link Status
> > > RU: Running CR: Carrier OK
> > > NQ: Queue Stopped HA: Hardware Arbitration
> > >
> > > I temporally change to the following to avoid that.
> > > if ((with_link &&
> > > !np->multi_channel &&
> > > list_empty(&ndp->channel_queue)) || np->multi_channel) {
> > >
> > > > + spin_lock_irqsave(&ndp->lock, flags);
> > > > + list_add_tail_rcu(&nc->link,
> > > > + &ndp->channel_queue);
> > > > + spin_unlock_irqrestore(&ndp->lock, flags);
> > > > +
> > > > + netdev_dbg(ndp->ndev.dev,
> > > > + "NCSI: Channel %u added to queue (link %s)\n",
> > > > + nc->id,
> > > > + ncm->data[2] & 0x1 ? "up" : "down");
> > > > + }
> > > > +
> > > > + spin_unlock_irqrestore(&nc->lock, cflags);
> > > > +
> > > > + if (with_link && !np->multi_channel)
> > > > + break;
> > >
> > > Similar issue here. As we are using break, so each package will configure one active TX.
> > >
> >
> > I believe this is handled properly in ncsi_channel_is_tx() in the most
> > recent revision.
>
> I saw this issue with the last revision. I was using the wrong email to reply.
>
> > > > }
> > > > + if (with_link && !ndp->multi_package)
> > > > + break;
> > > > }
> > > >
> > > > - if (!found) {
> > > > + if (list_empty(&ndp->channel_queue) && found) {
> > > > + netdev_info(ndp->ndev.dev,
> > > > + "NCSI: No channel with link found, configuring channel %u\n",
> > > > + found->id);
> > > > + spin_lock_irqsave(&ndp->lock, flags);
> > > > + list_add_tail_rcu(&found->link, &ndp->channel_queue);
> > > > + spin_unlock_irqrestore(&ndp->lock, flags);
> > > > + } else if (!found) {
> > > > netdev_warn(ndp->ndev.dev,
> > > > - "NCSI: No channel found with link\n");
> > > > + "NCSI: No channel found to configure!\n");
> > > > ncsi_report_link(ndp, true);
> > > > return -ENODEV;
> > > > }
> > >
> > > Also, for deselect package handler function, do we want to set to inactive here?
> > > If we just change the state, the cached data still keeps the old value. If the new
> > > ncsi_reset_dev() function is handling one by one, can we skip this part?
> >
> > Technically yes we could skip the state change here since
> > ncsi_reset_dev() will have already done it. However if we send a DP
> > command via some other means then it is probably best to ensure we treat
> > all channels on that package as inactive.
>
> When I tested, if I didn't comment out the state change in response handler,
> ncsi_reset_dev() function will not handle properly and some channels got into
> invisible state and at the end we lost those selectable channels.
Well that's not good :)
The deselect package command should only be sent once all channels on a
package have become inactive, so I wouldn't expect it to interfere with
ncsi_reset_dev(), but perhaps this gets combined with the issues sending
netlink commands close together. I'll investigate, if I'm lucky this will
be resolved with the same fixes.
>
> > > static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
> > > {
> > > struct ncsi_rsp_pkt *rsp;
> > > struct ncsi_dev_priv *ndp = nr->ndp;
> > > struct ncsi_package *np;
> > > struct ncsi_channel *nc;
> > > unsigned long flags;
> > >
> > > /* Find the package */
> > > rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
> > > ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
> > > &np, NULL);
> > > if (!np)
> > > return -ENODEV;
> > >
> > > /* Change state of all channels attached to the package */
> > > NCSI_FOR_EACH_CHANNEL(np, nc) {
> > > spin_lock_irqsave(&nc->lock, flags);
> > > nc->state = NCSI_CHANNEL_INACTIVE;
> > >
> > > spin_unlock_irqrestore(&nc->lock, flags);
> > > }
> > >
> > > return 0;
> > > }
> > >
> > >
>
>
^ permalink raw reply
* Re: [PATCH net] net: phy: Allow BCM54616S PHY to setup internal TX/RX clock delay
From: Tao Ren @ 2018-11-05 23:03 UTC (permalink / raw)
To: Florian Fainelli, Andrew Lunn, David S . Miller,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: openbmc@lists.ozlabs.org
In-Reply-To: <4844a371-ed1f-9f74-1674-e649a9283f12@gmail.com>
On 11/5/18 2:40 PM, Florian Fainelli wrote:
> I will let David be the judge whether this is appropriate as a bugfix
> (thus targeting the "net" tree) or a feature, which would have to wait
> for net-next to re-open.
Sure.
>> Signed-off-by: Tao Ren <taoren@fb.com>
>
> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Thank you Florian for the quick review!
Thanks,
Tao Ren
^ permalink raw reply
* [PATCH net] net: bpfilter: fix iptables failure if bpfilter_umh is disabled
From: Taehee Yoo @ 2018-11-05 13:31 UTC (permalink / raw)
To: davem, netdev; +Cc: daniel, ast, pablo, fw, ap420073
When iptables command is executed, ip_{set/get}sockopt() try to upload
bpfilter.ko if bpfilter is enabled. if it couldn't find bpfilter.ko,
command is failed.
bpfilter.ko is generated if CONFIG_BPFILTER_UMH is enabled.
ip_{set/get}sockopt() only checks CONFIG_BPFILTER.
So that if CONFIG_BPFILTER is enabled and CONFIG_BPFILTER_UMH is disabled,
iptables command is always failed.
test config:
CONFIG_BPFILTER=y
# CONFIG_BPFILTER_UMH is not set
test command:
%iptables -L
iptables: No chain/target/match by that name.
Fixes: d2ba09c17a06 ("net: add skeleton of bpfilter kernel module")
Signed-off-by: Taehee Yoo <ap420073@gmail.com>
---
net/ipv4/ip_sockglue.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 26c36cccabdc..fffcc130900e 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1246,7 +1246,7 @@ int ip_setsockopt(struct sock *sk, int level,
return -ENOPROTOOPT;
err = do_ip_setsockopt(sk, level, optname, optval, optlen);
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
if (optname >= BPFILTER_IPT_SO_SET_REPLACE &&
optname < BPFILTER_IPT_SET_MAX)
err = bpfilter_ip_set_sockopt(sk, optname, optval, optlen);
@@ -1559,7 +1559,7 @@ int ip_getsockopt(struct sock *sk, int level,
int err;
err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0);
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
if (optname >= BPFILTER_IPT_SO_GET_INFO &&
optname < BPFILTER_IPT_GET_MAX)
err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
@@ -1596,7 +1596,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
err = do_ip_getsockopt(sk, level, optname, optval, optlen,
MSG_CMSG_COMPAT);
-#ifdef CONFIG_BPFILTER
+#if IS_ENABLED(CONFIG_BPFILTER_UMH)
if (optname >= BPFILTER_IPT_SO_GET_INFO &&
optname < BPFILTER_IPT_GET_MAX)
err = bpfilter_ip_get_sockopt(sk, optname, optval, optlen);
--
2.17.1
^ permalink raw reply related
* Re: [PATCH net] net: phy: Allow BCM54616S PHY to setup internal TX/RX clock delay
From: Florian Fainelli @ 2018-11-05 22:40 UTC (permalink / raw)
To: Tao Ren, Andrew Lunn, David S . Miller, netdev, linux-kernel; +Cc: openbmc
In-Reply-To: <20181105223540.1897084-1-taoren@fb.com>
On 11/5/18 2:35 PM, Tao Ren wrote:
> This patch allows users to enable/disable internal TX and/or RX clock
> delay for BCM54616S PHYs so as to satisfy RGMII timing specifications.
>
> On a particular platform, whether TX and/or RX clock delay is required
> depends on how PHY connected to the MAC IP. This requirement can be
> specified through "phy-mode" property in the platform device tree.
>
> The patch is inspired by commit 733336262b28 ("net: phy: Allow BCM5481x
> PHYs to setup internal TX/RX clock delay").
I will let David be the judge whether this is appropriate as a bugfix
(thus targeting the "net" tree) or a feature, which would have to wait
for net-next to re-open.
>
> Signed-off-by: Tao Ren <taoren@fb.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> drivers/net/phy/broadcom.c | 18 ++++++++++++++++--
> 1 file changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
> index e86ea105c802..704537010453 100644
> --- a/drivers/net/phy/broadcom.c
> +++ b/drivers/net/phy/broadcom.c
> @@ -92,7 +92,7 @@ static int bcm54612e_config_init(struct phy_device *phydev)
> return 0;
> }
>
> -static int bcm5481x_config(struct phy_device *phydev)
> +static int bcm54xx_config_clock_delay(struct phy_device *phydev)
> {
> int rc, val;
>
> @@ -429,7 +429,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
> ret = genphy_config_aneg(phydev);
>
> /* Then we can set up the delay. */
> - bcm5481x_config(phydev);
> + bcm54xx_config_clock_delay(phydev);
>
> if (of_property_read_bool(np, "enet-phy-lane-swap")) {
> /* Lane Swap - Undocumented register...magic! */
> @@ -442,6 +442,19 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
> return ret;
> }
>
> +static int bcm54616s_config_aneg(struct phy_device *phydev)
> +{
> + int ret;
> +
> + /* Aneg firsly. */
> + ret = genphy_config_aneg(phydev);
> +
> + /* Then we can set up the delay. */
> + bcm54xx_config_clock_delay(phydev);
> +
> + return ret;
> +}
> +
> static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
> {
> int val;
> @@ -636,6 +649,7 @@ static struct phy_driver broadcom_drivers[] = {
> .features = PHY_GBIT_FEATURES,
> .flags = PHY_HAS_INTERRUPT,
> .config_init = bcm54xx_config_init,
> + .config_aneg = bcm54616s_config_aneg,
> .ack_interrupt = bcm_phy_ack_intr,
> .config_intr = bcm_phy_config_intr,
> }, {
>
--
Florian
^ permalink raw reply
* Re: [PATCH 1/6] phy: Add max_bitrate attribute & phy_get_max_bitrate()
From: Faiz Abbas @ 2018-11-05 13:22 UTC (permalink / raw)
To: Marc Kleine-Budde, linux-kernel, devicetree, netdev, linux-can
Cc: wg, robh+dt, mark.rutland, kishon
In-Reply-To: <1e708b81-ed63-7dbf-3120-d256c0ec76c6@pengutronix.de>
Hi Marc,
On Monday 05 November 2018 05:17 PM, Marc Kleine-Budde wrote:
> On 11/05/2018 12:14 PM, Faiz Abbas wrote:
>> Hi,
>>
>> On Monday 05 November 2018 03:07 PM, Marc Kleine-Budde wrote:
>>> On 11/05/2018 07:27 AM, Faiz Abbas wrote:
>>>> I remove the transceiver child node binding documentation in patch 5/6.
>>>>
>>>> The existing implementation is pretty limiting as it just has a child
>>>> node with no associated device. What if a transceiver requires its own
>>>> configurations before it can start sending/receiving messages (for
>>>> example, my usecase requires it to pull the standby line low)?
>>>>
>>>> I think that can be solved by implementing the transceiver as a phy and
>>>> exposing a generic get_max_bitrate API. That way, the transceiver device
>>>> can do all its startup configuration in the phy probe function.
>>>>
>>>> In any case, do suggest if you have a better idea on how to implement
>>>> pull gpio low requirement.
>>>
>>> As long as we don't have any proper transceiver/phy driver, that does
>>> more than swtich on/off a GPIO, please add a "xceiver" regulator to your
>>> driver. Look for:
>>>
>>>> devm_regulator_get(&pdev->dev, "xceiver");
>>>
>>
>> The transceiver is not specific to m_can. The pull down would be
>> required even if it were connected to some other controller.
>
> Ok, this is a quite common pattern. For the fsl/nxp boards we add the
> regulator to the board dts. See "imx28-evk.dts" for example:
>
>> can0: can@80032000 {
>> pinctrl-names = "default";
>> pinctrl-0 = <&can0_pins_a>;
>> xceiver-supply = <®_can_3v3>;
>> status = "okay";
>> };
>>
>> can1: can@80034000 {
>> pinctrl-names = "default";
>> pinctrl-0 = <&can1_pins_a>;
>> xceiver-supply = <®_can_3v3>;
>> status = "okay";
>> };
>
Ok. Will implement that in v2.
Thanks,
Faiz
^ permalink raw reply
* [PATCH net] net: phy: Allow BCM54616S PHY to setup internal TX/RX clock delay
From: Tao Ren @ 2018-11-05 22:35 UTC (permalink / raw)
To: Andrew Lunn, Florian Fainelli, David S . Miller, netdev,
linux-kernel
Cc: Tao Ren, openbmc
This patch allows users to enable/disable internal TX and/or RX clock
delay for BCM54616S PHYs so as to satisfy RGMII timing specifications.
On a particular platform, whether TX and/or RX clock delay is required
depends on how PHY connected to the MAC IP. This requirement can be
specified through "phy-mode" property in the platform device tree.
The patch is inspired by commit 733336262b28 ("net: phy: Allow BCM5481x
PHYs to setup internal TX/RX clock delay").
Signed-off-by: Tao Ren <taoren@fb.com>
---
drivers/net/phy/broadcom.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index e86ea105c802..704537010453 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -92,7 +92,7 @@ static int bcm54612e_config_init(struct phy_device *phydev)
return 0;
}
-static int bcm5481x_config(struct phy_device *phydev)
+static int bcm54xx_config_clock_delay(struct phy_device *phydev)
{
int rc, val;
@@ -429,7 +429,7 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
ret = genphy_config_aneg(phydev);
/* Then we can set up the delay. */
- bcm5481x_config(phydev);
+ bcm54xx_config_clock_delay(phydev);
if (of_property_read_bool(np, "enet-phy-lane-swap")) {
/* Lane Swap - Undocumented register...magic! */
@@ -442,6 +442,19 @@ static int bcm5481_config_aneg(struct phy_device *phydev)
return ret;
}
+static int bcm54616s_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Aneg firsly. */
+ ret = genphy_config_aneg(phydev);
+
+ /* Then we can set up the delay. */
+ bcm54xx_config_clock_delay(phydev);
+
+ return ret;
+}
+
static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
{
int val;
@@ -636,6 +649,7 @@ static struct phy_driver broadcom_drivers[] = {
.features = PHY_GBIT_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = bcm54xx_config_init,
+ .config_aneg = bcm54616s_config_aneg,
.ack_interrupt = bcm_phy_ack_intr,
.config_intr = bcm_phy_config_intr,
}, {
--
2.17.1
^ permalink raw reply related
* Re: [PATCH v2 3/3] b43: Use cordic algorithm from kernel library
From: Arend van Spriel @ 2018-11-05 22:11 UTC (permalink / raw)
To: Michael Büsch, Priit Laes
Cc: linux-kernel, netdev, linux-wireless, David S. Miller, Kalle Valo,
b43-dev
In-Reply-To: <20181105223909.61860cdd@wiggum>
On 11/5/2018 10:39 PM, Michael Büsch wrote:
> On Mon, 5 Nov 2018 21:37:18 +0200
> Priit Laes <plaes@plaes.org> wrote:
>
>> Kernel library has a common cordic algorithm which is identical
>> to internally implementatd one, so use it and drop the duplicate
>> implementation.
>>
>> Signed-off-by: Priit Laes <plaes@plaes.org>
>
>
> This looks nice.
> But what is the testing status of this?
> Has this been tested on actual b43-LP hardware?
>
> Is the replacement algorithm exactly the same, or are there slight
> differences (e.g. in corner cases)?
Hi Michael,
I recall doing a comparison between the algorithms and thought I put
that in the original commit message. However, it is not there. It is not
exactly the same as in b43 so there are difference for certain angles,
most results are the same however. This implementation is slightly more
accurate on the full scale.
^ permalink raw reply
* Re: Help with the BPF verifier
From: Arnaldo Carvalho de Melo @ 2018-11-05 12:33 UTC (permalink / raw)
To: Yonghong Song
Cc: Edward Cree, Daniel Borkmann, Jiri Olsa, Martin Lau,
Alexei Starovoitov, Linux Networking Development Mailing List
In-Reply-To: <83be6d5e-a868-9a83-a03d-b2e6d71e9333@fb.com>
Em Fri, Nov 02, 2018 at 09:27:52PM +0000, Yonghong Song escreveu:
>
>
> On 11/2/18 8:42 AM, Edward Cree wrote:
> > On 02/11/18 15:02, Arnaldo Carvalho de Melo wrote:
> >> Yeah, didn't work as well:
> >
> >> And the -vv in 'perf trace' didn't seem to map to further details in the
> >> output of the verifier debug:
> > Yeah for log_level 2 you probably need to make source-level changes to either
> > perf or libbpf (I think the latter). It's annoying that essentially no tools
> > plumb through an option for that, someone should fix them ;-)
> >
> >> libbpf: -- BEGIN DUMP LOG ---
> >> libbpf:
> >> 0: (bf) r6 = r1
> >> 1: (bf) r1 = r10
> >> 2: (07) r1 += -328
> >> 3: (b7) r7 = 64
> >> 4: (b7) r2 = 64
> >> 5: (bf) r3 = r6
> >> 6: (85) call bpf_probe_read#4
> >> 7: (79) r1 = *(u64 *)(r10 -320)
> >> 8: (15) if r1 == 0x101 goto pc+4
> >> R0=inv(id=0) R1=inv(id=0) R6=ctx(id=0,off=0,imm=0) R7=inv64 R10=fp0,call_-1
> >> 9: (55) if r1 != 0x2 goto pc+22
> >> R0=inv(id=0) R1=inv2 R6=ctx(id=0,off=0,imm=0) R7=inv64 R10=fp0,call_-1
> >> 10: (bf) r1 = r6
> >> 11: (07) r1 += 16
> >> 12: (05) goto pc+2
> >> 15: (79) r3 = *(u64 *)(r1 +0)
> >> dereference of modified ctx ptr R1 off=16 disallowed
> > Aha, we at least got a different error message this time.
> > And indeed llvm has done that optimisation, rather than the more obvious
> > 11: r3 = *(u64 *)(r1 +16)
> > because it wants to have lots of reads share a single insn. You may be able
> > to defeat that optimisation by adding compiler barriers, idk. Maybe someone
> > with llvm knowledge can figure out how to stop it (ideally, llvm would know
> > when it's generating for bpf backend and not do that). -O0? ¯\_(ツ)_/¯
>
> The optimization mostly likes below:
> br1:
> ...
> r1 += 16
> goto merge
> br2:
> ...
> r1 += 20
> goto merge
> merge:
> *(u64 *)(r1 + 0)
>
> The compiler tries to merge common loads. There is no easy way to
> stop this compiler optimization without turning off a lot of other
> optimizations. The easiest way is to add barriers
> __asm__ __volatile__("": : :"memory")
> after the ctx memory access to prevent their down stream merging.
Great, this made it work:
cat /home/acme/git/perf/tools/perf/examples/bpf/augmented_raw_syscalls.c
#include <stdio.h>
#include <linux/socket.h>
/* bpf-output associated map */
struct bpf_map SEC("maps") __augmented_syscalls__ = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = __NR_CPUS__,
};
struct syscall_enter_args {
unsigned long long common_tp_fields;
long syscall_nr;
unsigned long args[6];
};
struct syscall_exit_args {
unsigned long long common_tp_fields;
long syscall_nr;
long ret;
};
struct augmented_filename {
unsigned int size;
int reserved;
char value[256];
};
#define SYS_OPEN 2
#define SYS_OPENAT 257
SEC("raw_syscalls:sys_enter")
int sys_enter(struct syscall_enter_args *args)
{
struct {
struct syscall_enter_args args;
struct augmented_filename filename;
} augmented_args;
unsigned int len = sizeof(augmented_args);
const void *filename_arg = NULL;
probe_read(&augmented_args.args, sizeof(augmented_args.args), args);
switch (augmented_args.args.syscall_nr) {
case SYS_OPEN: filename_arg = (const void *)args->args[0];
__asm__ __volatile__("": : :"memory");
break;
case SYS_OPENAT: filename_arg = (const void *)args->args[1];
break;
default:
return 0;
}
if (filename_arg != NULL) {
augmented_args.filename.reserved = 0;
augmented_args.filename.size = probe_read_str(&augmented_args.filename.value,
sizeof(augmented_args.filename.value),
filename_arg);
if (augmented_args.filename.size < sizeof(augmented_args.filename.value)) {
len -= sizeof(augmented_args.filename.value) - augmented_args.filename.size;
len &= sizeof(augmented_args.filename.value) - 1;
}
} else {
len = sizeof(augmented_args.args);
}
perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, &augmented_args, len);
return 0;
}
SEC("raw_syscalls:sys_exit")
int sys_exit(struct syscall_exit_args *args)
{
struct syscall_exit_args augmented_args;
probe_read(&augmented_args, sizeof(augmented_args), args);
return augmented_args.syscall_nr == SYS_OPEN || augmented_args.syscall_nr == SYS_OPENAT;
}
license(GPL);
Now I have both open and openat getting the right
[root@jouet perf]# trace -e tools/perf/examples/bpf/augmented_raw_syscalls.c sleep 1
LLVM: dumping tools/perf/examples/bpf/augmented_raw_syscalls.o
0.000 ( 0.010 ms): sleep/15794 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC) = 3
0.028 ( 0.005 ms): sleep/15794 openat(dfd: CWD, filename: /lib64/libc.so.6, flags: CLOEXEC) = 3
0.241 ( 0.005 ms): sleep/15794 open(filename: /usr/lib/locale/locale-archive, flags: CLOEXEC) = 3
[root@jouet perf]#
[root@jouet perf]# trace -e tools/perf/examples/bpf/augmented_raw_syscalls.o cat /etc/passwd > /dev/null
0.000 ( 0.010 ms): cat/15918 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC) = 3
0.028 ( 0.006 ms): cat/15918 openat(dfd: CWD, filename: /lib64/libc.so.6, flags: CLOEXEC) = 3
0.241 ( 0.007 ms): cat/15918 open(filename: /usr/lib/locale/locale-archive, flags: CLOEXEC) = 3
0.289 ( 0.004 ms): cat/15918 openat(dfd: CWD, filename: /etc/passwd) = 3
[root@jouet perf]#
[root@jouet perf]# readelf -SW tools/perf/examples/bpf/augmented_raw_syscalls.o
There are 11 section headers, starting at offset 0x438:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .strtab STRTAB 0000000000000000 000376 0000bd 00 0 0 1
[ 2] .text PROGBITS 0000000000000000 000040 000000 00 AX 0 0 4
[ 3] raw_syscalls:sys_enter PROGBITS 0000000000000000 000040 000138 00 AX 0 0 8
[ 4] .relraw_syscalls:sys_enter REL 0000000000000000 000360 000010 10 10 3 8
[ 5] raw_syscalls:sys_exit PROGBITS 0000000000000000 000178 000070 00 AX 0 0 8
[ 6] maps PROGBITS 0000000000000000 0001e8 000038 00 WA 0 0 4
[ 7] license PROGBITS 0000000000000000 000220 000004 00 WA 0 0 1
[ 8] version PROGBITS 0000000000000000 000224 000004 00 WA 0 0 4
[ 9] .llvm_addrsig LOOS+0xfff4c03 0000000000000000 000370 000006 00 E 10 0 1
[10] .symtab SYMTAB 0000000000000000 000228 000138 18 1 7 8
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
p (processor specific)
[root@jouet perf]#
> > Alternatively, your prog looks short enough that maybe you could kick the C
> > habit and write it directly in eBPF asm, that way no-one is optimising things
> > behind your back. (I realise this option won't appeal to everyone ;-)
>
> The LLVM supports BPF inline assembly as well. Some examples here
> https://github.com/llvm-mirror/llvm/blob/master/test/CodeGen/BPF/inline_asm.ll
> You may try it for selective ctx access to work around some
> compiler optimizations. I personally have not used it yet and actually
> not sure whether it actually works or not :-)
I will take a look at it, but the simple barrier right after the first ctx
access did the trick for me, probably I'll cook some ctx accessor macros to
make this transparent.
Now to make -e open,openat to set up filters via a map, get that
augmented_raw_syscalls.c to be added automatically to the evlist, etc.
- Arnaldo
> > The reason the verifier disallows this, iirc, is because it needs to be able
> > to rewrite the offsets on ctx accesses (see convert_ctx_accesses()) in case > underlying kernel struct doesn't match the layout of the ctx ABI.
> To do this
> > it needs the ctx offset to live entirely in the insn doing the access,
> > otherwise different paths could lead to the same insn accessing different ctx
> > offsets with different fixups needed — can't be done.
> >
> > -Ed
> >
^ permalink raw reply
* Re: [PATCH v2 3/3] b43: Use cordic algorithm from kernel library
From: Michael Büsch @ 2018-11-05 21:39 UTC (permalink / raw)
To: Priit Laes
Cc: linux-kernel, netdev, linux-wireless, David S. Miller, Kalle Valo,
b43-dev
In-Reply-To: <77709642dacd9d855618bd9c2f3a56a88e881eaa.1541446422.git-series.plaes@plaes.org>
[-- Attachment #1: Type: text/plain, Size: 515 bytes --]
On Mon, 5 Nov 2018 21:37:18 +0200
Priit Laes <plaes@plaes.org> wrote:
> Kernel library has a common cordic algorithm which is identical
> to internally implementatd one, so use it and drop the duplicate
> implementation.
>
> Signed-off-by: Priit Laes <plaes@plaes.org>
This looks nice.
But what is the testing status of this?
Has this been tested on actual b43-LP hardware?
Is the replacement algorithm exactly the same, or are there slight
differences (e.g. in corner cases)?
--
Michael
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* SCTP on RH 5.7
From: David Laight @ 2018-11-05 11:48 UTC (permalink / raw)
To: netdev@vger.kernel.org
Why do our customers insist on trying to use SCTP on RH 5.7 with its
ancient 2.6.18 kernel.
Not surprising they are getting issues!
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox