From patchwork Tue Dec 4 14:13:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711847 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2912614E2 for ; Tue, 4 Dec 2018 14:16:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 18EC52A780 for ; Tue, 4 Dec 2018 14:16:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0C1542AA03; Tue, 4 Dec 2018 14:16:35 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C64A32A780 for ; Tue, 4 Dec 2018 14:16:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726699AbeLDOPg (ORCPT ); Tue, 4 Dec 2018 09:15:36 -0500 Received: from mail-pg1-f193.google.com ([209.85.215.193]:37985 "EHLO mail-pg1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726693AbeLDOPf (ORCPT ); Tue, 4 Dec 2018 09:15:35 -0500 Received: by mail-pg1-f193.google.com with SMTP id g189so7433498pgc.5 for ; Tue, 04 Dec 2018 06:15:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=q2ylLGh6Iq+PMgkhPzStCcFhPdE9msJgMttiTaylZ70=; b=Gu7MFIGvTaYrfrkenXwy7xVKP9/qdLrVE9WD0EbvHbzMMBjs9YnFzLAUCNgk62FQ5D 23EKJWZ/pFS866IiltTZ6+1CAiOBrseUGxKFoLHpTia/BFSBNBfD2IaYkd2r2vdu47IM rCbKtdAjvHNdluk9wq9QvgebNiyOvR0KM9B+Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=q2ylLGh6Iq+PMgkhPzStCcFhPdE9msJgMttiTaylZ70=; b=pZAStCskMZ1w1uE6RqlgxcYNSRTT5v2Hg6usgbUnQFy8bhgbhLopHd17urAi3UHnb0 oRengmna5XTmoTVKLM5+IPmCqEyto9jNd3F7+Rq7BA5Bn76iOsov0UUM6tDQ1S4KVzTY ig6YPLrornZk77NiFyfmYGEVAfRyasuGAIsxzpq2kCi1vxB/kBTtWTSSC0dbQUHrok3y /ST4WYDbZwg3rLL1g8kUIqXZCXK5812H9C7ZTL4DdwcLt9LRs4pxC0P9Jiad645NkqSE 22todCpFWy+4/wr/8Vlu744HoORwVSTtXlngIZAlnTL4uZEfy391zqvXxcc2kCLBIC6I ei7Q== X-Gm-Message-State: AA+aEWb587kP0A6KCb59Koj72OG1tFW2jbbssXe2QFWIjH9ZsS3+pMkX 3mxGK/tUvo/UgrvihJNBKe3bHA== X-Google-Smtp-Source: AFSGD/UhdL2mLZNhuMPwSiFSngnIPZVJTSIU5OaaFrN6NnPEyUb6NqkNTsJ6oKyodOhFcY35v5O6mg== X-Received: by 2002:a63:d208:: with SMTP id a8mr16632791pgg.77.1543932934038; Tue, 04 Dec 2018 06:15:34 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.31 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:33 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 1/6] net: lorawan: Add LoRaWAN socket module Date: Tue, 4 Dec 2018 22:13:38 +0800 Message-Id: <20181204141341.4353-2-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds a new address/protocol family for LoRaWAN network. It also implements the the functions and maps to Datagram socket for LoRaWAN unconfirmed data messages. Signed-off-by: Jian-Hong Pan --- V2: - Split the LoRaWAN class module patch in V1 into LoRaWAN socket and LoRaWAN Soft MAC modules - Add lorawan_netdev.h header file for network address related declaration - Use SPDX license identifiers V3: - Change the inline functions to a single line macro or just remove the decoration word - inline - Order local variables from longest to shortest line in the functions - Change mac_cb inline function to lrw_get_mac_cb macro V4: - Change lrw_get_mac_cb macro to an inline function - Use pr_fmt() instead of defining new printing log macros - Fix by coding style report from scripts/checkpatch.pl include/linux/lora/lorawan_netdev.h | 52 +++ net/lorawan/Kconfig | 10 + net/lorawan/Makefile | 2 + net/lorawan/socket.c | 686 ++++++++++++++++++++++++++++ 4 files changed, 750 insertions(+) create mode 100644 include/linux/lora/lorawan_netdev.h create mode 100644 net/lorawan/Kconfig create mode 100644 net/lorawan/Makefile create mode 100644 net/lorawan/socket.c diff --git a/include/linux/lora/lorawan_netdev.h b/include/linux/lora/lorawan_netdev.h new file mode 100644 index 000000000000..5bffb5164f95 --- /dev/null +++ b/include/linux/lora/lorawan_netdev.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ +/*- + * LoRaWAN stack related definitions + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#ifndef __LORAWAN_NET_DEVICE_H__ +#define __LORAWAN_NET_DEVICE_H__ + +enum { + LRW_ADDR_APPEUI, + LRW_ADDR_DEVEUI, + LRW_ADDR_DEVADDR, +}; + +struct lrw_addr_in { + int addr_type; + union { + u64 app_eui; + u64 dev_eui; + u32 devaddr; + }; +}; + +struct sockaddr_lorawan { + sa_family_t family; /* AF_LORAWAN */ + struct lrw_addr_in addr_in; +}; + +/** + * lrw_mac_cb - This structure holds the control buffer (cb) of sk_buff + * + * @devaddr: the LoRaWAN device address of this LoRaWAN hardware + */ +struct lrw_mac_cb { + u32 devaddr; +}; + +/** + * lrw_get_mac_cb - Get the LoRaWAN MAC control buffer of the sk_buff + * @skb: the exchanging sk_buff + * + * Return: the pointer of LoRaWAN MAC control buffer + */ +static inline struct lrw_mac_cb *lrw_get_mac_cb(struct sk_buff *skb) +{ + return (struct lrw_mac_cb *)skb->cb; +} + +#endif diff --git a/net/lorawan/Kconfig b/net/lorawan/Kconfig new file mode 100644 index 000000000000..bf6c9b77573b --- /dev/null +++ b/net/lorawan/Kconfig @@ -0,0 +1,10 @@ +config LORAWAN + tristate "LoRaWAN Network support" + help + LoRaWAN defines low data rate, low power and long range wireless + wide area networks. It was designed to organize networks of automation + devices, such as sensors, switches and actuators. It can operate + multiple kilometers wide. + + Say Y here to compile LoRaWAN support into the kernel or say M to + compile it as a module. diff --git a/net/lorawan/Makefile b/net/lorawan/Makefile new file mode 100644 index 000000000000..8c923ca6541a --- /dev/null +++ b/net/lorawan/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_LORAWAN) += lorawan.o +lorawan-objs := socket.o diff --git a/net/lorawan/socket.c b/net/lorawan/socket.c new file mode 100644 index 000000000000..c1981ef5b067 --- /dev/null +++ b/net/lorawan/socket.c @@ -0,0 +1,686 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/*- + * LoRaWAN stack related definitions + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#define LORAWAN_MODULE_NAME "lorawan" + +#define pr_fmt(fmt) LORAWAN_MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include +#include /* For TIOCOUTQ/INQ */ +#include +#include + +/** + * dgram_sock - This structure holds the states of Datagram socket + * + * @sk: network layer representation of the socket + * sk must be the first member of dgram_sock + * @src_devaddr: the LoRaWAN device address for this connection + * @bound: this socket is bound or not + * @connected: this socket is connected to the destination or not + * @want_ack: this socket needs to ack for the connection or not + */ +struct dgram_sock { + struct sock sk; + u32 src_devaddr; + + u8 bound:1; + u8 connected:1; +}; + +static HLIST_HEAD(dgram_head); +static DEFINE_RWLOCK(dgram_lock); + +static struct dgram_sock * +dgram_sk(const struct sock *sk) +{ + return container_of(sk, struct dgram_sock, sk); +} + +static struct net_device * +lrw_get_dev_by_addr(struct net *net, u32 devaddr) +{ + __be32 be_addr = cpu_to_be32(devaddr); + struct net_device *ndev = NULL; + + rcu_read_lock(); + ndev = dev_getbyhwaddr_rcu(net, ARPHRD_LORAWAN, (char *)&be_addr); + if (ndev) + dev_hold(ndev); + rcu_read_unlock(); + + return ndev; +} + +static int +dgram_init(struct sock *sk) +{ + return 0; +} + +static void +dgram_close(struct sock *sk, long timeout) +{ + sk_common_release(sk); +} + +static int +dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct sockaddr_lorawan *addr = (struct sockaddr_lorawan *)uaddr; + struct dgram_sock *ro = dgram_sk(sk); + struct net_device *ndev; + int ret; + + lock_sock(sk); + ro->bound = 0; + + ret = -EINVAL; + if (len < sizeof(*addr)) + goto dgram_bind_end; + + if (addr->family != AF_LORAWAN) + goto dgram_bind_end; + + if (addr->addr_in.addr_type != LRW_ADDR_DEVADDR) + goto dgram_bind_end; + + pr_debug("%s: bind address %X\n", __func__, addr->addr_in.devaddr); + ndev = lrw_get_dev_by_addr(sock_net(sk), addr->addr_in.devaddr); + if (!ndev) { + ret = -ENODEV; + goto dgram_bind_end; + } + netdev_dbg(ndev, "%s: get ndev\n", __func__); + + if (ndev->type != ARPHRD_LORAWAN) { + ret = -ENODEV; + goto dgram_bind_end; + } + + ro->src_devaddr = addr->addr_in.devaddr; + ro->bound = 1; + ret = 0; + dev_put(ndev); + pr_debug("%s: bound address %X\n", __func__, ro->src_devaddr); + +dgram_bind_end: + release_sock(sk); + return ret; +} + +static int +lrw_dev_hard_header(struct sk_buff *skb, struct net_device *ndev, + const u32 src_devaddr, size_t len) +{ + /* TODO: Prepare the LoRaWAN sending header here */ + return 0; +} + +static int +dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) +{ + struct dgram_sock *ro = dgram_sk(sk); + struct net_device *ndev; + struct sk_buff *skb; + size_t hlen; + size_t tlen; + int ret; + + pr_debug("%s: going to send %zu bytes", __func__, size); + if (msg->msg_flags & MSG_OOB) { + pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); + return -EOPNOTSUPP; + } + + pr_debug("%s: check msg_name\n", __func__); + if (!ro->connected && !msg->msg_name) + return -EDESTADDRREQ; + else if (ro->connected && msg->msg_name) + return -EISCONN; + + pr_debug("%s: check bound\n", __func__); + if (!ro->bound) + ndev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_LORAWAN); + else + ndev = lrw_get_dev_by_addr(sock_net(sk), ro->src_devaddr); + + if (!ndev) { + pr_debug("no dev\n"); + ret = -ENXIO; + goto dgram_sendmsg_end; + } + + if (size > ndev->mtu) { + netdev_dbg(ndev, "size = %zu, mtu = %u\n", size, ndev->mtu); + ret = -EMSGSIZE; + goto dgram_sendmsg_end; + } + + netdev_dbg(ndev, "%s: create skb\n", __func__); + hlen = LL_RESERVED_SPACE(ndev); + tlen = ndev->needed_tailroom; + skb = sock_alloc_send_skb(sk, hlen + tlen + size, + msg->msg_flags & MSG_DONTWAIT, + &ret); + + if (!skb) + goto dgram_sendmsg_no_skb; + + skb_reserve(skb, hlen); + skb_reset_network_header(skb); + + ret = lrw_dev_hard_header(skb, ndev, 0, size); + if (ret < 0) + goto dgram_sendmsg_no_skb; + + ret = memcpy_from_msg(skb_put(skb, size), msg, size); + if (ret > 0) + goto dgram_sendmsg_err_skb; + + skb->dev = ndev; + skb->protocol = htons(ETH_P_LORAWAN); + + netdev_dbg(ndev, "%s: push skb to xmit queue\n", __func__); + ret = dev_queue_xmit(skb); + if (ret > 0) + ret = net_xmit_errno(ret); + netdev_dbg(ndev, "%s: pushed skb to xmit queue with ret=%d\n", + __func__, ret); + dev_put(ndev); + + return ret ?: size; + +dgram_sendmsg_err_skb: + kfree_skb(skb); +dgram_sendmsg_no_skb: + dev_put(ndev); + +dgram_sendmsg_end: + return ret; +} + +static int +dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len) +{ + DECLARE_SOCKADDR(struct sockaddr_lorawan *, saddr, msg->msg_name); + struct sk_buff *skb; + size_t copied = 0; + int err; + + skb = skb_recv_datagram(sk, flags, noblock, &err); + if (!skb) + goto dgram_recvmsg_end; + + copied = skb->len; + if (len < copied) { + msg->msg_flags |= MSG_TRUNC; + copied = len; + } + + err = skb_copy_datagram_msg(skb, 0, msg, copied); + if (err) + goto dgram_recvmsg_done; + + sock_recv_ts_and_drops(msg, sk, skb); + if (saddr) { + memset(saddr, 0, sizeof(*saddr)); + saddr->family = AF_LORAWAN; + saddr->addr_in.devaddr = lrw_get_mac_cb(skb)->devaddr; + *addr_len = sizeof(*saddr); + } + + if (flags & MSG_TRUNC) + copied = skb->len; + +dgram_recvmsg_done: + skb_free_datagram(sk, skb); + +dgram_recvmsg_end: + if (err) + return err; + return copied; +} + +static int +dgram_hash(struct sock *sk) +{ + pr_debug("%s\n", __func__); + write_lock_bh(&dgram_lock); + sk_add_node(sk, &dgram_head); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + write_unlock_bh(&dgram_lock); + + return 0; +} + +static void +dgram_unhash(struct sock *sk) +{ + pr_debug("%s\n", __func__); + write_lock_bh(&dgram_lock); + if (sk_del_node_init(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + write_unlock_bh(&dgram_lock); +} + +static int +dgram_connect(struct sock *sk, struct sockaddr *uaddr, int len) +{ + struct dgram_sock *ro = dgram_sk(sk); + + /* Nodes of LoRaWAN send data to a gateway only, then data is received + * and transferred to servers with the gateway's policy. + * So, the destination address is not used by nodes. + */ + lock_sock(sk); + ro->connected = 1; + release_sock(sk); + + return 0; +} + +static int +dgram_disconnect(struct sock *sk, int flags) +{ + struct dgram_sock *ro = dgram_sk(sk); + + lock_sock(sk); + ro->connected = 0; + release_sock(sk); + + return 0; +} + +static int +dgram_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + struct net_device *ndev = sk->sk_dst_cache->dev; + struct sk_buff *skb; + int amount; + int err; + + netdev_dbg(ndev, "%s: ioctl file (cmd=0x%X)\n", __func__, cmd); + switch (cmd) { + case SIOCOUTQ: + amount = sk_wmem_alloc_get(sk); + err = put_user(amount, (int __user *)arg); + break; + case SIOCINQ: + amount = 0; + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + if (skb) { + /* We will only return the amount of this packet + * since that is all that will be read. + */ + amount = skb->len; + } + spin_unlock_bh(&sk->sk_receive_queue.lock); + err = put_user(amount, (int __user *)arg); + break; + default: + err = -ENOIOCTLCMD; + } + + return err; +} + +static int +dgram_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + int val, len; + + if (level != SOL_LORAWAN) + return -EOPNOTSUPP; + + if (get_user(len, optlen)) + return -EFAULT; + + len = min_t(unsigned int, len, sizeof(int)); + + switch (optname) { + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen)) + return -EFAULT; + + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + +static int +dgram_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, unsigned int optlen) +{ + int val; + int err; + + err = 0; + + if (optlen < sizeof(int)) + return -EINVAL; + + if (get_user(val, (int __user *)optval)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + default: + err = -ENOPROTOOPT; + break; + } + + release_sock(sk); + + return err; +} + +static struct proto lrw_dgram_prot = { + .name = "LoRaWAN", + .owner = THIS_MODULE, + .obj_size = sizeof(struct dgram_sock), + .init = dgram_init, + .close = dgram_close, + .bind = dgram_bind, + .sendmsg = dgram_sendmsg, + .recvmsg = dgram_recvmsg, + .hash = dgram_hash, + .unhash = dgram_unhash, + .connect = dgram_connect, + .disconnect = dgram_disconnect, + .ioctl = dgram_ioctl, + .getsockopt = dgram_getsockopt, + .setsockopt = dgram_setsockopt, +}; + +static int +lrw_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + + if (sk) { + sock->sk = NULL; + sk->sk_prot->close(sk, 0); + } + + return 0; +} + +static int +lrw_sock_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) +{ + struct sockaddr_lorawan *addr = (struct sockaddr_lorawan *)uaddr; + struct sock *sk = sock->sk; + + pr_debug("%s: bind address %X\n", __func__, addr->addr_in.devaddr); + if (sk->sk_prot->bind) + return sk->sk_prot->bind(sk, uaddr, addr_len); + + return sock_no_bind(sock, uaddr, addr_len); +} + +static int +lrw_sock_connect(struct socket *sock, struct sockaddr *uaddr, + int addr_len, int flags) +{ + struct sock *sk = sock->sk; + + if (addr_len < sizeof(uaddr->sa_family)) + return -EINVAL; + + return sk->sk_prot->connect(sk, uaddr, addr_len); +} + +static int +lrw_ndev_ioctl(struct sock *sk, struct ifreq __user *arg, unsigned int cmd) +{ + struct net_device *ndev; + struct ifreq ifr; + int ret; + + pr_debug("%s: cmd %ud\n", __func__, cmd); + ret = -ENOIOCTLCMD; + + if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) + return -EFAULT; + + ifr.ifr_name[IFNAMSIZ - 1] = 0; + + dev_load(sock_net(sk), ifr.ifr_name); + ndev = dev_get_by_name(sock_net(sk), ifr.ifr_name); + + netdev_dbg(ndev, "%s: cmd %ud\n", __func__, cmd); + if (!ndev) + return -ENODEV; + + if (ndev->type == ARPHRD_LORAWAN && ndev->netdev_ops->ndo_do_ioctl) + ret = ndev->netdev_ops->ndo_do_ioctl(ndev, &ifr, cmd); + + if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq))) + ret = -EFAULT; + dev_put(ndev); + + return ret; +} + +static int +lrw_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + + pr_debug("%s: cmd %ud\n", __func__, cmd); + switch (cmd) { + case SIOCGSTAMP: + return sock_get_timestamp(sk, (struct timeval __user *)arg); + case SIOCGSTAMPNS: + return sock_get_timestampns(sk, (struct timespec __user *)arg); + case SIOCOUTQ: + case SIOCINQ: + if (!sk->sk_prot->ioctl) + return -ENOIOCTLCMD; + return sk->sk_prot->ioctl(sk, cmd, arg); + default: + return lrw_ndev_ioctl(sk, (struct ifreq __user *)arg, cmd); + } +} + +static int +lrw_sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) +{ + struct sock *sk = sock->sk; + + pr_debug("%s: going to send %zu bytes\n", __func__, len); + return sk->sk_prot->sendmsg(sk, msg, len); +} + +static const struct proto_ops lrw_dgram_ops = { + .family = PF_LORAWAN, + .owner = THIS_MODULE, + .release = lrw_sock_release, + .bind = lrw_sock_bind, + .connect = lrw_sock_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = sock_no_getname, + .poll = datagram_poll, + .ioctl = lrw_sock_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_common_setsockopt, + .getsockopt = sock_common_getsockopt, + .sendmsg = lrw_sock_sendmsg, + .recvmsg = sock_common_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +static int +lorawan_creat(struct net *net, struct socket *sock, int protocol, int kern) +{ + struct sock *sk; + int ret; + + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + + if (sock->type != SOCK_DGRAM) + return -EAFNOSUPPORT; + + /* Allocates enough memory for dgram_sock whose first member is sk */ + sk = sk_alloc(net, PF_LORAWAN, GFP_KERNEL, &lrw_dgram_prot, kern); + if (!sk) + return -ENOMEM; + + sock->ops = &lrw_dgram_ops; + sock_init_data(sock, sk); + sk->sk_family = PF_LORAWAN; + sock_set_flag(sk, SOCK_ZAPPED); + + if (sk->sk_prot->hash) { + ret = sk->sk_prot->hash(sk); + if (ret) { + sk_common_release(sk); + goto lorawan_creat_end; + } + } + + if (sk->sk_prot->init) { + ret = sk->sk_prot->init(sk); + if (ret) + sk_common_release(sk); + } + +lorawan_creat_end: + return ret; +} + +static const struct net_proto_family lorawan_family_ops = { + .owner = THIS_MODULE, + .family = PF_LORAWAN, + .create = lorawan_creat, +}; + +static int +lrw_dgram_deliver(struct net_device *ndev, struct sk_buff *skb) +{ + struct dgram_sock *ro; + struct sock *sk; + bool found; + int ret; + + ret = NET_RX_SUCCESS; + found = false; + + read_lock(&dgram_lock); + sk_for_each(sk, &dgram_head) { + ro = dgram_sk(sk); + if (cpu_to_le32(ro->src_devaddr) == *(__le32 *)ndev->dev_addr) { + found = true; + break; + } + } + read_unlock(&dgram_lock); + + if (!found) + goto lrw_dgram_deliver_err; + + skb = skb_share_check(skb, GFP_ATOMIC); + if (!skb) + return NET_RX_DROP; + + if (sock_queue_rcv_skb(sk, skb) < 0) + goto lrw_dgram_deliver_err; + + return ret; + +lrw_dgram_deliver_err: + kfree_skb(skb); + ret = NET_RX_DROP; + return ret; +} + +static int +lorawan_rcv(struct sk_buff *skb, struct net_device *ndev, + struct packet_type *pt, struct net_device *orig_ndev) +{ + if (!netif_running(ndev)) + goto lorawan_rcv_drop; + + if (!net_eq(dev_net(ndev), &init_net)) + goto lorawan_rcv_drop; + + if (ndev->type != ARPHRD_LORAWAN) + goto lorawan_rcv_drop; + + if (skb->pkt_type != PACKET_OTHERHOST) + return lrw_dgram_deliver(ndev, skb); + +lorawan_rcv_drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +static struct packet_type lorawan_packet_type = { + .type = htons(ETH_P_LORAWAN), + .func = lorawan_rcv, +}; + +static int __init +lrw_sock_init(void) +{ + int ret; + + pr_info("module inserted\n"); + ret = proto_register(&lrw_dgram_prot, 1); + if (ret) + goto lrw_sock_init_end; + + /* Tell SOCKET that we are alive */ + ret = sock_register(&lorawan_family_ops); + if (ret) + goto lrw_sock_init_err; + + dev_add_pack(&lorawan_packet_type); + ret = 0; + goto lrw_sock_init_end; + +lrw_sock_init_err: + proto_unregister(&lrw_dgram_prot); + +lrw_sock_init_end: + return 0; +} + +static void __exit +lrw_sock_exit(void) +{ + dev_remove_pack(&lorawan_packet_type); + sock_unregister(PF_LORAWAN); + proto_unregister(&lrw_dgram_prot); + pr_info("module removed\n"); +} + +module_init(lrw_sock_init); +module_exit(lrw_sock_exit); + +MODULE_AUTHOR("Jian-Hong Pan, "); +MODULE_DESCRIPTION("LoRaWAN socket kernel module"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS_NETPROTO(PF_LORAWAN); From patchwork Tue Dec 4 14:13:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711823 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D2ACE14E2 for ; Tue, 4 Dec 2018 14:15:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C24492A780 for ; Tue, 4 Dec 2018 14:15:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B65532A895; Tue, 4 Dec 2018 14:15:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 991452A780 for ; Tue, 4 Dec 2018 14:15:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726713AbeLDOPj (ORCPT ); Tue, 4 Dec 2018 09:15:39 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:41025 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726706AbeLDOPh (ORCPT ); Tue, 4 Dec 2018 09:15:37 -0500 Received: by mail-pg1-f194.google.com with SMTP id 70so7429080pgh.8 for ; Tue, 04 Dec 2018 06:15:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1qTK7eo+F9woQYTaQMAKzg3EGdvHcywuYbLGRNZvzTY=; b=OQwdjQgVRBJwEyLrdYBj7mq8dYG/M6M/mznos1R0E01NL+Xjc5RwH+RHaIRpTC/j7d bKOR5AqgGy1llutSnc9qMySvd5wmNg81/BLLJ6TL3cH7UgZWmR6UEVKOfDmTwb/mJ5Ir iwn2jsBny66PzLYwIcraxCanEHUgO/WwH+aWw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1qTK7eo+F9woQYTaQMAKzg3EGdvHcywuYbLGRNZvzTY=; b=toKLh8YUhgEFMkpNTi2TZSHxGROXL0J8cdQKu+2dp0kecp6BIC3HivsqqTHoZqEXnI Kbh1DlcfXMZHbtW/nEwF4dQgxrnL6W9HfD0SfcpJBTRpZQzFQhQPRzO3pHIQTOcv2Y06 3ww9ViLXJqrY9k/UVbMcbHphohB6YKPmxit/DpU5wIavEBAFvPmmZpB+QKwTX1v5J5Cj gD01++abOil/pkeUzh3811ilb3Pehr/UfuA2MBlDzxMGA7RmYyVputhk3Cn6tB1xlnbr I8Uy5uqWdX/d9C7LUNMfln8tGvNKP7D79mBHshu5JC/xYRTol7sscRiXX4LbaMDAbj6s tFYg== X-Gm-Message-State: AA+aEWaH20peg+j8FDA9gRgFFjAZ78/YzGWgGNMTh2hn92l8vxC00s+3 Mx8vDccp2EvzLfkumTzTb9stBw== X-Google-Smtp-Source: AFSGD/XlTbkn1QZMkiZAg874zWUdUjjC7oNVYKUmbviUyg/u4n2/Cftx4+30ueC3nTYDnESVPqghSg== X-Received: by 2002:a63:6ac5:: with SMTP id f188mr17018931pgc.165.1543932936468; Tue, 04 Dec 2018 06:15:36 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.34 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:36 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 2/6] net: lorawan: Add LoRaWAN API declaration for LoRa devices Date: Tue, 4 Dec 2018 22:13:39 +0800 Message-Id: <20181204141341.4353-3-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add public LoRaWAN API for compatible LoRa device drivers. Signed-off-by: Jian-Hong Pan --- 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 V3: - Remove the unused lrw_random_addr function V4: - Fix by coding style report from scripts/checkpatch.pl include/linux/lora/lorawan.h | 131 +++++++++++++++++++++++++++++++++++ 1 file changed, 131 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..201f27521655 --- /dev/null +++ b/include/linux/lora/lorawan.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ +/*- + * LoRaWAN compatible hardware's definitions + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#ifndef __LORAWAN_H__ +#define __LORAWAN_H__ + +#include + +/* 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 *hw); + void (*stop)(struct lrw_hw *hw); + + int (*xmit_async)(struct lrw_hw *hw, struct sk_buff *skb); + int (*set_txpower)(struct lrw_hw *hw, s32 pwr); + int (*set_frq)(struct lrw_hw *hw, u32 frq); + int (*set_dr)(struct lrw_hw *hw, struct lrw_dr *dr); + int (*start_rx_window)(struct lrw_hw *hw, u32 delay); + int (*set_state)(struct lrw_hw *hw, u8 state); +}; + +struct lrw_hw *lrw_alloc_hw(size_t priv_data_len, struct lrw_operations *ops); +void lrw_free_hw(struct lrw_hw *hw); +int lrw_register_hw(struct lrw_hw *hw); +void lrw_unregister_hw(struct lrw_hw *hw); +void lrw_rx_irqsave(struct lrw_hw *hw, struct sk_buff *skb); +void lrw_xmit_complete(struct lrw_hw *hw, struct sk_buff *skb); + +void lrw_set_deveui(struct lrw_hw *hw, u64 eui); +u64 lrw_get_deveui(struct lrw_hw *hw); +void lrw_set_appeui(struct lrw_hw *hw, u64 eui); +u64 lrw_get_appeui(struct lrw_hw *hw); +void lrw_set_devaddr(struct lrw_hw *hw, u32 eui); +u32 lrw_get_devaddr(struct lrw_hw *hw); + +enum { + LRW_APPKEY, + LRW_NWKSKEY, + LRW_APPSKEY, +}; + +#define LRW_KEY_LEN 16 + +int lrw_set_key(struct lrw_hw *hw, u8 type, u8 *key, size_t key_len); + +#endif From patchwork Tue Dec 4 14:13:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711845 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C9C111731 for ; Tue, 4 Dec 2018 14:16:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B9A082A780 for ; Tue, 4 Dec 2018 14:16:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AB8AF2A895; Tue, 4 Dec 2018 14:16:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0E26F2A780 for ; Tue, 4 Dec 2018 14:16:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726720AbeLDOPk (ORCPT ); Tue, 4 Dec 2018 09:15:40 -0500 Received: from mail-pg1-f194.google.com ([209.85.215.194]:43860 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726417AbeLDOPk (ORCPT ); Tue, 4 Dec 2018 09:15:40 -0500 Received: by mail-pg1-f194.google.com with SMTP id v28so7424734pgk.10 for ; Tue, 04 Dec 2018 06:15:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QT/jwpU9ivKbEFe6HNlLtAKOm/2gOedicUVpenMpNWY=; b=eck9SQUYRqWwcMG4f3ZkERiQhM1+bbdR5dLK/Kn6uTChNAQDbmOUD1V9MrkXIlDM/Q kpDcS94Pl2Ups0YlXtwGUSwYcnN41sZp/Cx7RbJkYeBXNxhW7hfrVILQjKlXW1FUsrFf V2OuhFAdQ6DQzVnKZ0F1TEy2fXXi/TJpRwUEQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QT/jwpU9ivKbEFe6HNlLtAKOm/2gOedicUVpenMpNWY=; b=WijIB+gqo2xHsR9TFtGwzMq9vfYcCzKuL2Eooe8mg1t6qQV7iW0tCNeXAk8wKqM27F UYQVruO4oYBtuNPwd72M/lc7UU5f5tmjeMoQ4uIkezzJyUxsTcTRZkWc8xvuEB8Th9mJ c5GxSHcjQF4ql1a5a3yayw7iUuc3ukT/+ktwcfD00d8KewfzxWbOHYdkUuUBdIRJVBAO GAqGGkW2adb0319PUDKJPo0D6MnFMzD5KbuOhMzRcHcPVAHjRBORExmQDFVv0mYQg14C QxwFc067SRsCCFL6EZve75qOmOskn+1O/ICxCW0CJMNewmsEo1tbnkiGifqurRQdbt5x urSw== X-Gm-Message-State: AA+aEWbxTa1ecIbgtJqgiP7sTOEC8lJ9h7BAzQ/k8igg3PLUT4OCGOgW LqFZ0b0K+Jt18RgWsWXrjd5oXw== X-Google-Smtp-Source: AFSGD/V4gYHI9BZv96TnW3s4KyhpGGmdE6ZqrgX3h+wHapy2NxajIkXX/3EYORxfIQI96wZWvR4i+g== X-Received: by 2002:a63:6c48:: with SMTP id h69mr16052195pgc.139.1543932938838; Tue, 04 Dec 2018 06:15:38 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:38 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 3/6] net: maclorawan: Add maclorawan module declaration Date: Tue, 4 Dec 2018 22:13:40 +0800 Message-Id: <20181204141341.4353-4-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add the maclorawan header file for common APIs in the module. Signed-off-by: Jian-Hong Pan --- V2: - Split the LoRaWAN class module patch in V1 into LoRaWAN socket and LoRaWAN Soft MAC modules - Use SPDX license identifiers V4: - Fix typo in comments - Fix by coding style report from scripts/checkpatch.pl net/maclorawan/maclorawan.h | 200 ++++++++++++++++++++++++++++++++++++ 1 file changed, 200 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..572c26c7cf40 --- /dev/null +++ b/net/maclorawan/maclorawan.h @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ +/*- + * LoRaWAN soft MAC + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#ifndef __MAC_LORAWAN_H__ +#define __MAC_LORAWAN_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 milliseconds + * @rx2_window: RX2 window opening time in milliseconds + * @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; + + u8 tx_should_ack; + u8 retry; + u8 state; + spinlock_t state_lock; /* lock of the session's state */ + + 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 + * @ss_list_lock: lock of the session list + * @_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; /* lock of the session list */ + struct lrw_session *_cur_ss; + u8 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_sync_skcipher *nwks_skc_tfm; + struct crypto_sync_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 *lrw_st); +void lrw_free_ss(struct lrw_session *ss); +void lrw_del_ss(struct lrw_session *ss); +int lrw_start_hw(struct lrw_struct *lrw_st); +void lrw_stop_hw(struct lrw_struct *lrw_st); +void lrw_prepare_tx_frame(struct lrw_session *ss); +void lrw_xmit(unsigned long data); +void lrw_rx_work(struct work_struct *work); + +#endif From patchwork Tue Dec 4 14:13:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711831 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1685118A7 for ; Tue, 4 Dec 2018 14:15:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 08C592A780 for ; Tue, 4 Dec 2018 14:15:46 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id F0AEF2AA03; Tue, 4 Dec 2018 14:15:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 578E22A780 for ; Tue, 4 Dec 2018 14:15:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726748AbeLDOPn (ORCPT ); Tue, 4 Dec 2018 09:15:43 -0500 Received: from mail-pg1-f196.google.com ([209.85.215.196]:46967 "EHLO mail-pg1-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726745AbeLDOPn (ORCPT ); Tue, 4 Dec 2018 09:15:43 -0500 Received: by mail-pg1-f196.google.com with SMTP id w7so7421595pgp.13 for ; Tue, 04 Dec 2018 06:15:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ytv1cVXpRljGfxPS2GlCpo+dCCVwID6zj0f5fmzf1uM=; b=cxFvVBhvR03pzVBh5BBs+bt8HA+laXWMlIBnoX641jWSzhVI1Dfn+kaXcRtB+mrPcH U4tIPSrundX+c/3ARbT7q+aHz/1rciydBf+Q30yn2mos8H8PbWdPG3Kt4syBhAR3lHn7 FKQ+pS8bCBsJgDwnI/HenGp5i8xwuefE8SbJ8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ytv1cVXpRljGfxPS2GlCpo+dCCVwID6zj0f5fmzf1uM=; b=rs1ItmBhKCPXy4JKowmfc86MBphTvQ4EhF92eO5qRii7zPzy0uobp3gx46biVKwCwu hlcvrPGz8NqG3CR8Oefkb6dO7g6skTJtmVs/oohz1CCXVZJowPLglqEZxcSN7ZPOCvFX cZE3D1W/ggWBHde81AYNPZSuG7uLVXdVdpjclMpbczSboyqA82z0FMaDADAA2WtL7OFJ Ams4y7uV6TS64Jvi0xFByEc54JsyLzHXsc3PXMFyJTE35gDKUQ0nQIQpVHoAnPrDeNuE RiV2yPAZfYD5cfJvloLA4BG6bs9B8X3IiUy1T8mMFLl/63rkBRpN237D3E4ZyDrsj4zh KyOw== X-Gm-Message-State: AA+aEWZS5AnP3cShA/CXjZ7mXoh5p0tZ172JpUgBXu7DegT5LF49ouQy AhqjOCLwZgRP5yCH69bVhpbLcQ== X-Google-Smtp-Source: AFSGD/XfACY41/aOz7I7Z4emP5ODuI3J85+x+j7KicG3oIVyanrXqtXeVg1bb/L4PTNhFZiHXBwyQg== X-Received: by 2002:a63:42c1:: with SMTP id p184mr16715011pga.202.1543932941254; Tue, 04 Dec 2018 06:15:41 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:40 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 4/6] net: maclorawan: Implement the crypto of maclorawan module Date: Tue, 4 Dec 2018 22:13:41 +0800 Message-Id: <20181204141341.4353-5-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Implement the crypto for encryption/decryption and message integrity code (MIC) according to LoRaWAN(TM) Specification Ver. 1.0.2. Signed-off-by: Jian-Hong Pan --- V2: - Split the LoRaWAN class module patch in V1 into LoRaWAN socket and LoRaWAN Soft MAC modules - Rename the lrwsec files to crypto files - Modify for Big/Little-Endian - Use SPDX license identifiers V3: - Order local variables from longest to shortest line in the functions V4: - Fix by coding style report from scripts/checkpatch.pl net/maclorawan/crypto.c | 212 ++++++++++++++++++++++++++++++++++++++++ net/maclorawan/crypto.h | 27 +++++ 2 files changed, 239 insertions(+) create mode 100644 net/maclorawan/crypto.c create mode 100644 net/maclorawan/crypto.h diff --git a/net/maclorawan/crypto.c b/net/maclorawan/crypto.c new file mode 100644 index 000000000000..0ae9d211cd14 --- /dev/null +++ b/net/maclorawan/crypto.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/*- + * LoRaWAN soft MAC + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#include +#include +#include +#include "crypto.h" + +struct crypto_shash * +lrw_mic_key_setup(u8 *k, size_t k_len) +{ + struct crypto_shash *tfm; + char *algo = "cmac(aes)"; + int err; + + tfm = crypto_alloc_shash(algo, 0, 0); + if (!IS_ERR(tfm)) { + err = crypto_shash_setkey(tfm, k, k_len); + if (err) { + crypto_free_shash(tfm); + tfm = NULL; + } + } + + return tfm; +} + +int +lrw_aes_cmac(struct crypto_shash *tfm, u8 *bz, u8 *data, size_t len, u8 *out) +{ + SHASH_DESC_ON_STACK(desc, tfm); + int err; + + desc->tfm = tfm; + + err = crypto_shash_init(desc); + if (err) + goto lrw_aes_cmac_end; + + err = crypto_shash_update(desc, bz, 16); + if (err) + goto lrw_aes_cmac_end; + + err = crypto_shash_update(desc, data, len); + if (err) + goto lrw_aes_cmac_end; + + err = crypto_shash_final(desc, out); + +lrw_aes_cmac_end: + return err; +} + +int +lrw_set_bzero(u8 dir, u32 devaddr, u32 fcnt, u8 len, u8 *bz) +{ + __le32 le_devaddr = cpu_to_le32(devaddr); + __le32 le_fcnt = cpu_to_le32(fcnt); + + bz[0] = 0x49; + memset(bz + 1, 0x00, 4); + bz[5] = dir; + memcpy(bz + 6, &le_devaddr, 4); + memcpy(bz + 10, &le_fcnt, 4); + bz[14] = 0x00; + bz[15] = len; + + return 0; +} + +int +lrw_calc_mic(struct crypto_shash *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len, u8 *mic4) +{ + u8 mic[16]; + u8 bz[16]; + int err; + + /* According to LoRaWAN Specification Version 1.0.2 + * - 4.4 Massege Integrity Code (MIC) + */ + lrw_set_bzero(dir, devaddr, fcnt, len, bz); + err = lrw_aes_cmac(tfm, bz, buf, len, mic); + if (!err) + memcpy(mic4, mic, 4); + + return err; +} + +void +lrw_mic_key_free(struct crypto_shash *tfm) +{ + crypto_free_shash(tfm); +} + +struct crypto_sync_skcipher * +lrw_aes_enc_key_setup(char *algo, u8 *k, size_t k_len) +{ + struct crypto_sync_skcipher *tfm; + int err; + + tfm = crypto_alloc_sync_skcipher(algo, 0, CRYPTO_ALG_ASYNC); + if (!IS_ERR(tfm)) { + err = crypto_sync_skcipher_setkey(tfm, k, k_len); + if (err) { + crypto_free_sync_skcipher(tfm); + tfm = NULL; + } + } + + return tfm; +} + +struct crypto_sync_skcipher * +lrw_encrypt_key_setup(u8 *k, size_t k_len) +{ + return lrw_aes_enc_key_setup("cbc(aes)", k, k_len); +} + +int +lrw_aes_enc(struct crypto_sync_skcipher *tfm, u8 *in, size_t len, u8 *out) +{ + SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm); + struct scatterlist src, dst; + u8 iv[16]; + int err; + + memset(iv, 0, 16); + /* The buffer for sg_init_one cannot be a global or const local + * (will confuse the scatterlist) + */ + sg_init_one(&src, in, len); + sg_init_one(&dst, out, len); + + skcipher_request_set_sync_tfm(req, tfm); + skcipher_request_set_callback(req, 0, NULL, NULL); + skcipher_request_set_crypt(req, &src, &dst, len, iv); + err = crypto_skcipher_encrypt(req); + skcipher_request_zero(req); + + return err; +} + +#define LRW_SEQUENCE_OF_BLOCK_LEN 16 + +int +lrw_set_sob(u8 dir, u32 devaddr, u32 fcnt, u8 index, u8 *sob) +{ + __le32 le_devaddr = cpu_to_le32(devaddr); + __le32 _fcnt = cpu_to_le32(fcnt); + + sob[0] = 0x01; + memset(sob + 1, 0x00, 4); + sob[5] = dir; + memcpy(sob + 6, &le_devaddr, 4); + memcpy(sob + 10, &_fcnt, 4); + sob[14] = 0x00; + sob[15] = index; + + return 0; +} + +int +lrw_encrypt_sob(struct crypto_sync_skcipher *tfm, u8 *sob) +{ + return lrw_aes_enc(tfm, sob, LRW_SEQUENCE_OF_BLOCK_LEN, sob); +} + +int +lrw_encrypt_buf(struct crypto_sync_skcipher *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len) +{ + u8 sob[LRW_SEQUENCE_OF_BLOCK_LEN]; + u8 i, j; + + /* According to LoRaWAN Specification Version 1.0.2 + * - 4.3.3 MAC Frame Payload Encryption (FRMPayload) + */ + for (i = 0; (i * LRW_SEQUENCE_OF_BLOCK_LEN) < len; i++) { + lrw_set_sob(dir, devaddr, fcnt, i, sob); + lrw_encrypt_sob(tfm, sob); + for (j = 0; (i * LRW_SEQUENCE_OF_BLOCK_LEN + j) < len; j++) + buf[i * LRW_SEQUENCE_OF_BLOCK_LEN + j] ^= sob[j]; + } + + return 0; +} + +int +lrw_decrypt_buf(struct crypto_sync_skcipher *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len) +{ + /* According to XOR swap algorithm */ + return lrw_encrypt_buf(tfm, dir, devaddr, fcnt, buf, len); +} + +void +lrw_aes_enc_key_free(struct crypto_sync_skcipher *tfm) +{ + crypto_free_sync_skcipher(tfm); +} + +void +lrw_encrypt_key_free(struct crypto_sync_skcipher *tfm) +{ + lrw_aes_enc_key_free(tfm); +} diff --git a/net/maclorawan/crypto.h b/net/maclorawan/crypto.h new file mode 100644 index 000000000000..22dd810040c0 --- /dev/null +++ b/net/maclorawan/crypto.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ +/*- + * LoRaWAN soft MAC + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#ifndef __LORAWAN_CRYPTO_H__ +#define __LORAWAN_CRYPTO_H__ + +#include +#include + +struct crypto_shash *lrw_mic_key_setup(u8 *k, size_t k_len); +int lrw_calc_mic(struct crypto_shash *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len, u8 *mic4); +void lrw_mic_key_free(struct crypto_shash *tfm); + +struct crypto_sync_skcipher *lrw_encrypt_key_setup(u8 *k, size_t k_len); +int lrw_encrypt_buf(struct crypto_sync_skcipher *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len); +int lrw_decrypt_buf(struct crypto_sync_skcipher *tfm, + u8 dir, u32 devaddr, u32 fcnt, u8 *buf, size_t len); +void lrw_encrypt_key_free(struct crypto_sync_skcipher *tfm); + +#endif From patchwork Tue Dec 4 14:13:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711843 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1FBDC1731 for ; Tue, 4 Dec 2018 14:16:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0DF4D2A7CD for ; Tue, 4 Dec 2018 14:16:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0136A2B72C; Tue, 4 Dec 2018 14:16:17 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C9D672A7CD for ; Tue, 4 Dec 2018 14:16:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725956AbeLDOQM (ORCPT ); Tue, 4 Dec 2018 09:16:12 -0500 Received: from mail-pl1-f194.google.com ([209.85.214.194]:33807 "EHLO mail-pl1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726745AbeLDOPp (ORCPT ); Tue, 4 Dec 2018 09:15:45 -0500 Received: by mail-pl1-f194.google.com with SMTP id w4so8378028plz.1 for ; Tue, 04 Dec 2018 06:15:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ShFSLXO3qbst0EX1gB1OPNZEaQ1wgw6CZuDfa1QUbyk=; b=QtBSlQOtDg97KVxWhRa8IUUlzkFSAl2OFWXSV27a3lQ2yFsy4OSWykCVD8wWyKWP7B 9j1OX59VclaTXKSgtqPs2m0QIfYfFeuzAOcB2GAo0PBeVBQMfJudhm+Qspg0Aga1zIOH 2qEsvClmA77zq4ZAUZFE7Dl9kYLDGSZic7AOA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ShFSLXO3qbst0EX1gB1OPNZEaQ1wgw6CZuDfa1QUbyk=; b=cv7ZNNk+tgZredxMHYpDcS7QhqbSTOjUIC9VSvDoTAlmXLzizIu07G03PBaS9qFIVb 4sQx59ckyd/PVSmZR4Nl22DhocKF3FCE2QAhDrozJvmZyu+GsSPdD36v6bxyQOpIqM8s j9IBfZJW13RAyrc8Hv321nhxmGqNTQbivQwZCjcLxZg2inf+SN9zwd2sNJdhFRkoid8F yTs8ZM9GOpcBfDVIH2CR9YVZLh+Dy8wrC+fiA/r/fBc4CZKTRz9cRvkwZK1AqmVq5vfg m3dnirpnIW8mJ47ZZ9H4Ck5VKG7vVS+AOcMU8ulZhwbDy8ynHRu6VdHDDqUP79LniG6r M6kg== X-Gm-Message-State: AA+aEWaHk6mZVR8+s6ckVhFWOI7F6+msomW+x25r429g9A39zo/KtfJL UoyZYuUTZMBnJ3EzXVWTqmoX9ljpMMox5Q== X-Google-Smtp-Source: AFSGD/UKr/OyQ1DkOdtMDZbPz0mcREUfMbjP29z50OzC6u5NgzmP7MLd6nW8JsWz36TwOG1DLikz1g== X-Received: by 2002:a17:902:5ac7:: with SMTP id g7mr20429711plm.212.1543932943708; Tue, 04 Dec 2018 06:15:43 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.41 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:43 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 5/6] net: maclorawan: Implement maclorawan class module Date: Tue, 4 Dec 2018 22:13:42 +0800 Message-Id: <20181204141341.4353-6-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- V2: - Split the LoRaWAN class module patch in V1 into LoRaWAN socket and LoRaWAN Soft MAC modules - Modify for Big/Little-Endian - Use SPDX license identifiers V3: - Remove the decoration word - inline of the functions - Order local variables from longest to shortest line in the functions - Change the calling mac_cb function to lrw_get_mac_cb macro V4: - Fix the delay period between RX window#1 and window#2 - Fix by coding style report from scripts/checkpatch.pl net/maclorawan/Kconfig | 14 + net/maclorawan/Makefile | 2 + net/maclorawan/mac.c | 518 ++++++++++++++++++++++++++++++++++ net/maclorawan/main.c | 605 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1139 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..d700314edf26 --- /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..70e6923bf63e --- /dev/null +++ b/net/maclorawan/mac.c @@ -0,0 +1,518 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/*- + * LoRaWAN soft MAC + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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(*ss), GFP_KERNEL); + if (!ss) + goto lrw_alloc_ss_end; + + ss->lrw_st = lrw_st; + ss->devaddr = lrw_st->devaddr; + INIT_LIST_HEAD(&ss->entry); + + ss->tx_should_ack = false; + ss->retry = 3; + spin_lock_init(&ss->state_lock); + INIT_WORK(&ss->timeout_work, rx_timeout_work); + +lrw_alloc_ss_end: + return ss; +} + +void +lrw_free_ss(struct lrw_session *ss) +{ + netdev_dbg(ss->lrw_st->ndev, "%s\n", __func__); + if (ss->tx_skb) + consume_skb(ss->tx_skb); + netdev_dbg(ss->lrw_st->ndev, "%s: free rx skb\n", __func__); + if (ss->rx_skb) + consume_skb(ss->rx_skb); + + netdev_dbg(ss->lrw_st->ndev, "%s: free ss\n", __func__); + kfree(ss); +} + +void +lrw_del_ss(struct lrw_session *ss) +{ + netdev_dbg(ss->lrw_st->ndev, "%s\n", __func__); + list_del(&ss->entry); + lrw_free_ss(ss); +} + +void +lrw_del_all_ss(struct lrw_struct *lrw_st) +{ + struct lrw_session *ss, *tmp; + + mutex_lock(&lrw_st->ss_list_lock); + lrw_st->_cur_ss = NULL; + list_for_each_entry_safe(ss, tmp, &lrw_st->ss_list, entry) { + del_timer(&ss->timer); + lrw_del_ss(ss); + } + mutex_unlock(&lrw_st->ss_list_lock); +} + +void +lrw_ready_hw(struct lrw_struct *lrw_st) +{ + lrw_st->state = LRW_STATE_IDLE; +} + +int +lrw_start_hw(struct lrw_struct *lrw_st) +{ + int ret = 0; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + lrw_st->nwks_shash_tfm = lrw_mic_key_setup(lrw_st->nwkskey, + LRW_KEY_LEN); + lrw_st->nwks_skc_tfm = lrw_encrypt_key_setup(lrw_st->nwkskey, + LRW_KEY_LEN); + lrw_st->apps_skc_tfm = lrw_encrypt_key_setup(lrw_st->appskey, + LRW_KEY_LEN); + lrw_st->state = LRW_START; + ret = lrw_st->ops->start(&lrw_st->hw); + if (!ret) + lrw_ready_hw(lrw_st); + + return ret; +} + +void +lrw_stop_hw(struct lrw_struct *lrw_st) +{ + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + lrw_st->state = LRW_STOP; + netdev_dbg(lrw_st->ndev, "%s: going to stop hardware\n", __func__); + lrw_st->ops->stop(&lrw_st->hw); + + netdev_dbg(lrw_st->ndev, "%s: going to kill tasks & flush works", + __func__); + tasklet_kill(&lrw_st->xmit_task); + flush_work(&lrw_st->rx_work); + + netdev_dbg(lrw_st->ndev, "%s: going to delete all session\n", __func__); + lrw_del_all_ss(lrw_st); + + netdev_dbg(lrw_st->ndev, "%s: going to free mic tfm\n", __func__); + lrw_mic_key_free(lrw_st->nwks_shash_tfm); + netdev_dbg(lrw_st->ndev, "%s: going to free nwks tfm\n", __func__); + lrw_encrypt_key_free(lrw_st->nwks_skc_tfm); + netdev_dbg(lrw_st->ndev, "%s: going to free apps tfm\n", __func__); + lrw_encrypt_key_free(lrw_st->apps_skc_tfm); +} + +void +lrw_prepare_tx_frame(struct lrw_session *ss) +{ + struct lrw_struct *lrw_st = ss->lrw_st; + struct sk_buff *skb = ss->tx_skb; + u8 mhdr, fctrl, fport, mic[4]; + __le32 le_devaddr; + __le16 le_fcnt_up; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + /* Encrypt the plain buffer content */ + lrw_encrypt_buf(lrw_st->apps_skc_tfm, LRW_UPLINK, + ss->devaddr, ss->fcnt_up, skb->data, skb->len); + + /* Push FPort */ + if (skb->len) { + fport = ss->fport; + memcpy(skb_push(skb, LRW_FPORT_LEN), &fport, LRW_FPORT_LEN); + } + + /* Push FCnt_Up */ + le_fcnt_up = cpu_to_le16(ss->fcnt_up); + memcpy(skb_push(skb, 2), &le_fcnt_up, 2); + + /* Push FCtrl */ + fctrl = 0; + if (lrw_st->rx_should_ack) { + fctrl |= 0x20; + lrw_st->rx_should_ack = false; + } + memcpy(skb_push(skb, 1), &fctrl, 1); + + /* Push DevAddr */ + le_devaddr = cpu_to_le32(ss->devaddr); + memcpy(skb_push(skb, LRW_DEVADDR_LEN), &le_devaddr, LRW_DEVADDR_LEN); + + /* Push MHDR */ + mhdr = LRW_UNCONFIRMED_DATA_UP << 5; + if ((mhdr & (0x6 << 5)) == (0x4 << 5)) + ss->tx_should_ack = true; + memcpy(skb_push(skb, LRW_MHDR_LEN), &mhdr, LRW_MHDR_LEN); + + /* Put MIC */ + lrw_calc_mic(lrw_st->nwks_shash_tfm, LRW_UPLINK, + ss->devaddr, ss->fcnt_up, skb->data, skb->len, mic); + memcpy(skb_put(skb, LRW_MIC_LEN), mic, LRW_MIC_LEN); +} + +void +lrw_xmit(unsigned long data) +{ + struct lrw_struct *lrw_st = (struct lrw_struct *)data; + struct lrw_session *ss = lrw_st->_cur_ss; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + ss->state = LRW_XMITTING_SS; + lrw_st->ops->xmit_async(&lrw_st->hw, ss->tx_skb); +} + +void +lrw_parse_frame(struct lrw_session *ss, struct sk_buff *skb) +{ + struct lrw_fhdr *fhdr = &ss->rx_fhdr; + __le16 *p_fcnt; + + pr_debug("%s: %s\n", LORAWAN_MODULE_NAME, __func__); + + /* Get message type */ + fhdr->mtype = skb->data[0]; + skb_pull(skb, LRW_MHDR_LEN); + + /* Trim Device Address */ + skb_pull(skb, 4); + + /* Get frame control */ + fhdr->fctrl = skb->data[0]; + skb_pull(skb, 1); + + /* Ack the original TX frame if it should be acked */ + if (ss->tx_should_ack && (fhdr->fctrl & 0x20)) + ss->tx_should_ack = false; + + /* Get frame count */ + p_fcnt = (__le16 *)skb->data; + fhdr->fcnt = le16_to_cpu(*p_fcnt); + skb_pull(skb, 2); + + /* Get frame options */ + fhdr->fopts_len = fhdr->fctrl & 0xF; + if (fhdr->fopts_len > 0) { + memcpy(fhdr->fopts, skb->data, fhdr->fopts_len); + skb_pull(skb, fhdr->fopts_len); + } + + /* TODO: Parse frame options */ + + /* Remove message integrity code */ + skb_trim(skb, skb->len - LRW_MIC_LEN); +} + +struct lrw_session * +lrw_rx_skb_2_session(struct lrw_struct *lrw_st, struct sk_buff *rx_skb) +{ + struct lrw_session *ss; + __le16 *p_fcnt; + u16 fcnt; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + p_fcnt = (__le16 *)(rx_skb->data + 6); + fcnt = le16_to_cpu(*p_fcnt); + + /* Find the corresponding session */ + ss = lrw_st->_cur_ss; + + /* Frame count downlink check */ + if (fcnt >= (ss->fcnt_down & 0xFFFF)) + ss->rx_skb = rx_skb; + else + ss = NULL; + + return ss; +} + +void +lrw_rx_work(struct work_struct *work) +{ + struct lrw_struct *lrw_st; + struct lrw_session *ss; + struct sk_buff *skb; + + lrw_st = container_of(work, struct lrw_struct, rx_work); + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + skb = lrw_st->rx_skb_list.next; + skb_dequeue(&lrw_st->rx_skb_list); + + /* Check and parse the RX frame */ + ss = lrw_rx_skb_2_session(lrw_st, skb); + if (!ss) + goto lrw_rx_work_not_new_frame; + + lrw_parse_frame(ss, skb); + + /* Check the TX frame is acked or not */ + if (ss->tx_should_ack) { + ss->rx_skb = NULL; + goto lrw_rx_work_not_new_frame; + } + + /* The TX frame is acked or no need to be acked */ + del_timer(&ss->timer); + lrw_st->rx_should_ack = (ss->rx_fhdr.mtype & 0xC0) == 0x40; + + lrw_st->ndev->stats.rx_packets++; + lrw_st->ndev->stats.rx_bytes += ss->rx_skb->len; + + if (ss->rx_skb->len > 0) { + spin_lock_bh(&ss->state_lock); + ss->state = LRW_RXRECEIVED_SS; + spin_unlock_bh(&ss->state_lock); + + lrw_get_mac_cb(skb)->devaddr = lrw_st->devaddr; + netif_receive_skb(skb); + + ss->rx_skb = NULL; + } + + mutex_lock(&lrw_st->ss_list_lock); + lrw_st->fcnt_down = ss->rx_fhdr.fcnt; + lrw_st->_cur_ss = NULL; + lrw_del_ss(ss); + lrw_st->state = LRW_STATE_IDLE; + mutex_unlock(&lrw_st->ss_list_lock); + + return; + +lrw_rx_work_not_new_frame: + /* Drop the RX frame if checked failed */ + kfree_skb(skb); +} + +int +lrw_check_mic(struct crypto_shash *tfm, struct sk_buff *skb) +{ + u32 devaddr; + size_t len; + u8 cks[4]; + u16 fcnt; + u8 *buf; + u8 *mic; + + buf = skb->data; + devaddr = le32_to_cpu(*((__le32 *)(buf + LRW_MHDR_LEN))); + fcnt = le16_to_cpu(*(__le16 *)(buf + 6)); + len = skb->len - 4; + mic = skb->data + len; + + lrw_calc_mic(tfm, LRW_DOWNLINK, devaddr, fcnt, buf, len, cks); + + return (!memcmp(cks, mic, 4)); +} + +/** + * lrw_rx_irqsave - Tell LoRaWAN module that there is new received frame + * @hw: the LoRa device + * @skb: the new received frame + */ +void +lrw_rx_irqsave(struct lrw_hw *hw, struct sk_buff *skb) +{ + struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw); + u32 devaddr; + u8 mtype; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + mtype = skb->data[0] >> 5; + devaddr = le32_to_cpu(*(__le32 *)(skb->data + LRW_MHDR_LEN)); + + /* Check the frame is the downlink frame */ + if ((mtype == LRW_UNCONFIRMED_DATA_DOWN || + mtype == LRW_CONFIRMED_DATA_DOWN) && + devaddr == lrw_st->devaddr && + lrw_check_mic(lrw_st->nwks_shash_tfm, skb)) { + skb_queue_tail(&lrw_st->rx_skb_list, skb); + schedule_work(&lrw_st->rx_work); + } else { + kfree_skb(skb); + } +} +EXPORT_SYMBOL(lrw_rx_irqsave); + +static void +lrw_rexmit(struct timer_list *timer) +{ + struct lrw_session *ss = container_of(timer, struct lrw_session, timer); + struct lrw_struct *lrw_st = ss->lrw_st; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + lrw_st->state = LRW_STATE_TX; + lrw_xmit((unsigned long)lrw_st); +} + +static void +rx_timeout_work(struct work_struct *work) +{ + struct lrw_struct *lrw_st; + struct lrw_session *ss; + + ss = container_of(work, struct lrw_session, timeout_work); + lrw_st = ss->lrw_st; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + mutex_lock(&lrw_st->ss_list_lock); + lrw_st->_cur_ss = NULL; + lrw_st->state = LRW_STATE_IDLE; + lrw_del_ss(ss); + mutex_unlock(&lrw_st->ss_list_lock); +} + +static void +rx2_timeout_isr(struct timer_list *timer) +{ + struct lrw_session *ss = container_of(timer, struct lrw_session, timer); + struct lrw_struct *lrw_st = ss->lrw_st; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + /* Check TX is acked or not */ + if (!ss->tx_should_ack) { + spin_lock_bh(&ss->state_lock); + if (ss->state != LRW_RXRECEIVED_SS) + ss->state = LRW_RXTIMEOUT_SS; + spin_unlock_bh(&ss->state_lock); + + if (ss->state == LRW_RXTIMEOUT_SS) { + netdev_dbg(lrw_st->ndev, "%s: rx time out\n", __func__); + goto rx2_timeout_isr_no_retry_rx_frame; + } else { + return; + } + } + + /* Check the session need to be retransmitted or not */ + if (ss->retry > 0) { + ss->state = LRW_RETRANSMIT_SS; + ss->retry--; + + /* Start timer for ack timeout and retransmit */ + ss->timer.function = lrw_rexmit; + ss->timer.expires = jiffies_64 + ss->ack_timeout * HZ; + add_timer(&ss->timer); + } else { + /* Retry failed */ +rx2_timeout_isr_no_retry_rx_frame: + schedule_work(&ss->timeout_work); + } +} + +static void +rx2_delay_isr(struct timer_list *timer) +{ + struct lrw_session *ss = container_of(timer, struct lrw_session, timer); + struct lrw_struct *lrw_st = ss->lrw_st; + unsigned long delay; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + /* Start timer for RX2 window */ + ss->timer.function = rx2_timeout_isr; + delay = jiffies_64 + (ss->rx2_window + 20) * HZ / 1000 + HZ; + ss->timer.expires = delay; + add_timer(&ss->timer); + + /* Start LoRa hardware to RX2 window */ + ss->state = LRW_RX2_SS; + lrw_st->ops->start_rx_window(&lrw_st->hw, ss->rx2_window + 20); +} + +static void +rx1_delay_isr(struct timer_list *timer) +{ + struct lrw_session *ss = container_of(timer, struct lrw_session, timer); + struct lrw_struct *lrw_st = ss->lrw_st; + unsigned long delay; + + netdev_dbg(lrw_st->ndev, "%s\n", __func__); + + /* Start timer for RX_Delay2 - RX_Delay2 */ + ss->timer.function = rx2_delay_isr; + delay = jiffies_64 + (ss->rx_delay2 - ss->rx_delay1) * HZ; + 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..49beed5111b8 --- /dev/null +++ b/net/maclorawan/main.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/*- + * LoRaWAN soft MAC + * + * Copyright (c) 2018 Jian-Hong, Pan + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include "maclorawan.h" + +#define PHY_NAME "lora" + +/* Need to find a way to define or assign */ +#define LORAWAN_MTU 20 + +static struct class *lrw_sys_class; + +static void +lrw_if_setup(struct net_device *ndev) +{ + ndev->addr_len = LRW_DEVADDR_LEN; + memset(ndev->broadcast, 0xFF, ndev->addr_len); + ndev->type = ARPHRD_LORAWAN; + + ndev->hard_header_len = LRW_MHDR_LEN + LRW_FHDR_MAX_LEN + LRW_FPORT_LEN; + ndev->needed_tailroom = LRW_MIC_LEN; + + /** + * TODO: M should be a dynamic value defined by Regional Parameters, + * Being fixed for now. Going to be changed. + */ + ndev->mtu = LORAWAN_MTU; +} + +/** + * lrw_alloc_hw - Allocate a memory space for the LoRa device + * @priv_data_len: the private data size + * @lrw_operations: the implemented operations of the LoRa device + * + * Return: address of the LoRa device or NULL for failed + */ +struct lrw_hw * +lrw_alloc_hw(size_t priv_data_len, struct lrw_operations *ops) +{ + struct lrw_struct *lrw_st; + struct net_device *ndev; + int ret; + + if (WARN_ON(!ops || !ops->start || !ops->stop || !ops->xmit_async || + !ops->set_txpower || !ops->set_dr || + !ops->start_rx_window || !ops->set_state)) + return NULL; + + /* In memory it'll be like this: + * + * +-----------------------+ + * | struct net_device | + * +-----------------------+ + * | struct lrw_struct | + * +-----------------------+ + * | driver's private data | + * +-----------------------+ + */ + ndev = alloc_netdev(sizeof(struct lrw_struct) + priv_data_len, + PHY_NAME "%d", NET_NAME_ENUM, lrw_if_setup); + if (!ndev) + return ERR_PTR(-ENOMEM); + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) + goto lrw_alloc_hw_err; + + lrw_st = (struct lrw_struct *)netdev_priv(ndev); + lrw_st->ndev = ndev; + + lrw_st->state = LRW_STOP; + lrw_st->ops = ops; + lrw_st->hw.priv = (u8 *)lrw_st + sizeof(struct lrw_struct); + + ndev->flags |= IFF_NOARP; + ndev->features |= NETIF_F_HW_CSUM; + + return &lrw_st->hw; + +lrw_alloc_hw_err: + free_netdev(ndev); + return ERR_PTR(ret); +} +EXPORT_SYMBOL(lrw_alloc_hw); + +/** + * lrw_free_hw - Free the LoRa device's memory resource + * @hw: the LoRa device going to be freed + */ +void +lrw_free_hw(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + free_netdev(lrw_st->ndev); +} +EXPORT_SYMBOL(lrw_free_hw); + +/** + * lrw_set_deveui - Set the LoRa device's DevEUI + * @hw: the LoRa device going to be set + * @eui: the global end-device ID in IEEE EUI64 address space + */ +void +lrw_set_deveui(struct lrw_hw *hw, u64 eui) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + lrw_st->dev_eui = eui; +} +EXPORT_SYMBOL(lrw_set_deveui); + +/** + * lrw_get_deveui - Get the LoRa device's DevEUI + * @hw: the LoRa device going to be got from + * + * Return: the device's DevEUI in IEEE EUI64 address space + */ +u64 +lrw_get_deveui(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + return lrw_st->dev_eui; +} +EXPORT_SYMBOL(lrw_get_deveui); + +/** + * lrw_set_appeui - Set the LoRa device's AppEUI + * @hw: the LoRa device going to be set + * @eui: the global end-device ID in IEEE EUI64 address space + */ +void +lrw_set_appeui(struct lrw_hw *hw, u64 eui) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + lrw_st->app_eui = eui; +} +EXPORT_SYMBOL(lrw_set_appeui); + +/** + * lrw_get_appeui - Get the LoRa device's AppEUI + * @hw: the LoRa device going to be got from + * + * Return: the device's AppEUI in IEEE EUI64 address space + */ +u64 +lrw_get_appeui(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + return lrw_st->app_eui; +} +EXPORT_SYMBOL(lrw_get_appeui); + +/** + * lrw_set_devaddr - Set the LoRa device's address + * @hw: the LoRa device going to be set + * @devaddr: the device address + */ +void +lrw_set_devaddr(struct lrw_hw *hw, u32 devaddr) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + lrw_st->devaddr = devaddr; +} +EXPORT_SYMBOL(lrw_set_devaddr); + +/** + * lrw_get_devaddr - Get the LoRa device's address + * @hw: the LoRa device going to be got from + * + * Return: the device address + */ +u32 +lrw_get_devaddr(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st; + + lrw_st = container_of(hw, struct lrw_struct, hw); + return lrw_st->devaddr; +} +EXPORT_SYMBOL(lrw_get_devaddr); + +/** + * lrw_add_hw - Add a LoRaWAN hardware as a network device + * @lrw_st: the LoRa device going to be added + * + * Return: 0 / other number for success / failed + */ +static int +lrw_add_hw(struct lrw_struct *lrw_st) +{ + struct net_device *ndev = lrw_st->ndev; + __be32 be_addr; + int ret; + + lrw_st->fcnt_up = 0; + lrw_st->fcnt_down = 0; + lrw_st->_cur_ss = NULL; + + mutex_init(&lrw_st->ss_list_lock); + INIT_LIST_HEAD(&lrw_st->ss_list); + + tasklet_init(&lrw_st->xmit_task, lrw_xmit, (unsigned long)lrw_st); + INIT_WORK(&lrw_st->rx_work, lrw_rx_work); + + be_addr = cpu_to_be32(lrw_st->devaddr); + memcpy(ndev->perm_addr, &be_addr, ndev->addr_len); + memcpy(ndev->dev_addr, ndev->perm_addr, ndev->addr_len); + + write_pnet(&lrw_st->_net, &init_net); + ret = register_netdev(ndev); + + return ret; +} + +/** + * lrw_remove_hw - Remove a LoRaWAN hardware from a network device + * @lrw_st: the LoRa device going to be removed + */ +static void +lrw_remove_hw(struct lrw_struct *lrw_st) +{ + unregister_netdev(lrw_st->ndev); + tasklet_kill(&lrw_st->xmit_task); +} + +bool +ready2write(struct lrw_struct *lrw_st) +{ + bool status = false; + + if (!lrw_st->_cur_ss && lrw_st->state == LRW_STATE_IDLE) + status = true; + + return status; +} + +bool +ready2read(struct lrw_struct *lrw_st) +{ + struct lrw_session *ss; + bool status = false; + + if (!list_empty(&lrw_st->ss_list) && lrw_st->state != LRW_STOP) { + ss = list_first_entry(&lrw_st->ss_list, + struct lrw_session, + entry); + if (ss->state == LRW_RXRECEIVED_SS) + status = true; + } + + return status; +} + +static int +lrw_if_up(struct net_device *ndev) +{ + struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev); + int ret = -EBUSY; + + if (lrw_st->state == LRW_STOP) { + ret = lrw_start_hw(lrw_st); + netif_start_queue(ndev); + } + + return ret; +} + +static int +lrw_if_down(struct net_device *ndev) +{ + struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev); + + if (lrw_st->state != LRW_STOP) { + netif_stop_queue(ndev); + lrw_stop_hw(lrw_st); + } + + return 0; +} + +static netdev_tx_t +lrw_if_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev); + struct lrw_session *ss; + netdev_tx_t ret; + + ret = NETDEV_TX_OK; + + ss = lrw_alloc_ss(lrw_st); + if (!ss) + return NETDEV_TX_BUSY; + + mutex_lock(&lrw_st->ss_list_lock); + if (ready2write(lrw_st)) { + list_add_tail(&ss->entry, &lrw_st->ss_list); + lrw_st->state = LRW_STATE_TX; + lrw_st->_cur_ss = ss; + ss->fcnt_up = lrw_st->fcnt_up; + ss->fcnt_down = lrw_st->fcnt_down; + /* TODO: RX delay #1/#2 should be set by regional parameters */ + ss->rx_delay1 = 1; + ss->rx_delay2 = 2; + ss->rx1_window = 500; + ss->rx2_window = 500; + } else { + ret = NETDEV_TX_BUSY; + } + mutex_unlock(&lrw_st->ss_list_lock); + + if (ret == NETDEV_TX_OK) { + ss->state = LRW_INIT_SS; + ss->tx_skb = skb; + lrw_prepare_tx_frame(ss); + tasklet_schedule(&lrw_st->xmit_task); + } else { + lrw_free_ss(ss); + } + + return ret; +} + +static int +lrw_if_get_addr(struct lrw_struct *lrw_st, struct sockaddr_lorawan *addr) +{ + int ret = 0; + + switch (addr->addr_in.addr_type) { + case LRW_ADDR_DEVADDR: + addr->addr_in.devaddr = lrw_st->devaddr; + break; + case LRW_ADDR_DEVEUI: + addr->addr_in.dev_eui = lrw_st->dev_eui; + break; + case LRW_ADDR_APPEUI: + addr->addr_in.app_eui = lrw_st->app_eui; + break; + default: + ret = -ENOTSUPP; + } + + return ret; +} + +static int +lrw_if_set_addr(struct lrw_struct *lrw_st, struct sockaddr_lorawan *addr) +{ + struct lrw_hw *hw = &lrw_st->hw; + int ret = 0; + + if (netif_running(lrw_st->ndev)) + return -EBUSY; + + switch (addr->addr_in.addr_type) { + case LRW_ADDR_DEVADDR: + lrw_set_devaddr(hw, addr->addr_in.devaddr); + break; + case LRW_ADDR_DEVEUI: + lrw_set_deveui(hw, addr->addr_in.dev_eui); + break; + case LRW_ADDR_APPEUI: + lrw_set_appeui(hw, addr->addr_in.app_eui); + break; + default: + ret = -ENOTSUPP; + } + + return ret; +} + +static void +swap_bytes(u8 *dst, u8 *src, size_t l) +{ + /* Human reading is big-endian, but LoRaWAN is little-endian */ + unsigned int i; + + for (i = 0; i < l; i++) + dst[i] = src[l - i - 1]; +} + +int +lrw_set_key(struct lrw_hw *hw, u8 type, u8 *key, size_t key_len) +{ + struct lrw_struct *lrw_st; + int ret = 0; + + lrw_st = container_of(hw, struct lrw_struct, hw); + + netdev_dbg(lrw_st->ndev, "%s: type=%d\n", __func__, type); + if (lrw_st->state != LRW_STOP) + return -EINVAL; + + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, + 16, 1, key, key_len, true); + switch (type) { + case LRW_APPKEY: + swap_bytes(lrw_st->appkey, key, key_len); + break; + case LRW_NWKSKEY: + swap_bytes(lrw_st->nwkskey, key, key_len); + break; + case LRW_APPSKEY: + swap_bytes(lrw_st->appskey, key, key_len); + break; + default: + ret = -ENOTSUPP; + } + + return ret; +} +EXPORT_SYMBOL(lrw_set_key); + +int +lrw_get_key(struct lrw_hw *hw, u8 type, u8 *key, size_t key_len) +{ + struct lrw_struct *lrw_st; + int ret = 0; + + lrw_st = container_of(hw, struct lrw_struct, hw); + + netdev_dbg(lrw_st->ndev, "%s: type=%d\n", __func__, type); + switch (type) { + case LRW_APPKEY: + swap_bytes(key, lrw_st->appkey, key_len); + break; + case LRW_NWKSKEY: + swap_bytes(key, lrw_st->nwkskey, key_len); + break; + case LRW_APPSKEY: + swap_bytes(key, lrw_st->appskey, key_len); + break; + default: + ret = -ENOTSUPP; + } + + return ret; +} + +static int +lrw_if_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) +{ + struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev); + struct sockaddr_lorawan *addr; + int ret = 0; + + netdev_dbg(ndev, "%s: ioctl file (cmd=0x%X)\n", __func__, cmd); + + /* I/O control by each command */ + switch (cmd) { + /* Set & get the DevAddr, DevEUI and AppEUI */ + case SIOCSIFADDR: + addr = (struct sockaddr_lorawan *)&ifr->ifr_addr; + ret = lrw_if_set_addr(lrw_st, addr); + break; + case SIOCGIFADDR: + addr = (struct sockaddr_lorawan *)&ifr->ifr_addr; + ret = lrw_if_get_addr(lrw_st, addr); + break; + default: + ret = -ENOTSUPP; + } + + return ret; +} + +static int +lrw_if_set_mac(struct net_device *ndev, void *p) +{ + struct lrw_struct *lrw_st = NETDEV_2_LRW(ndev); + struct sockaddr *addr = p; + __be32 *be_addr; + + be_addr = (__be32 *)addr->sa_data; + + netdev_dbg(ndev, "%s: AF_TYPE:%d set mac address %X\n", + __func__, addr->sa_family, be32_to_cpu(*be_addr)); + + if (netif_running(ndev)) + return -EBUSY; + + lrw_set_devaddr(&lrw_st->hw, be32_to_cpu(*be_addr)); + memcpy(ndev->dev_addr, be_addr, ndev->addr_len); + + return 0; +} + +static const struct net_device_ops lrw_if_ops = { + .ndo_open = lrw_if_up, + .ndo_stop = lrw_if_down, + .ndo_start_xmit = lrw_if_start_xmit, + .ndo_do_ioctl = lrw_if_ioctl, + .ndo_set_mac_address = lrw_if_set_mac, +}; + +/** + * lrw_register_hw - Register as a LoRaWAN compatible device + * @hw: LoRa device going to be registered + * + * Return: 0 / negative number for success / error number + */ +int +lrw_register_hw(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw); + int ret; + + device_initialize(&lrw_st->dev); + dev_set_name(&lrw_st->dev, netdev_name(lrw_st->ndev)); + lrw_st->dev.class = lrw_sys_class; + lrw_st->dev.platform_data = lrw_st; + + ret = device_add(&lrw_st->dev); + if (ret) + goto lrw_register_hw_end; + + /* Add a LoRa device node as a network device */ + lrw_st->ndev->netdev_ops = &lrw_if_ops; + ret = lrw_add_hw(lrw_st); + if (!ret) + netdev_info(lrw_st->ndev, "register\n"); + +lrw_register_hw_end: + return ret; +} +EXPORT_SYMBOL(lrw_register_hw); + +/** + * lrw_unregister_hw - Unregister the LoRaWAN compatible device + * @hw: LoRa device going to be unregistered + */ +void +lrw_unregister_hw(struct lrw_hw *hw) +{ + struct lrw_struct *lrw_st = container_of(hw, struct lrw_struct, hw); + + netdev_info(lrw_st->ndev, "unregister\n"); + + /* Stop and remove the LoRaWAM hardware from system */ + if (lrw_st->state != LRW_STOP) + lrw_stop_hw(lrw_st); + device_del(&lrw_st->dev); + lrw_remove_hw(lrw_st); +} +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, "); +MODULE_DESCRIPTION("LoRaWAN soft MAC kernel module"); +MODULE_LICENSE("Dual BSD/GPL"); From patchwork Tue Dec 4 14:13:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jian-Hong Pan X-Patchwork-Id: 10711837 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 906E314E2 for ; Tue, 4 Dec 2018 14:16:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8263E2A780 for ; Tue, 4 Dec 2018 14:16:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 764852A895; Tue, 4 Dec 2018 14:16:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DD1E72A780 for ; Tue, 4 Dec 2018 14:16:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726351AbeLDOQA (ORCPT ); Tue, 4 Dec 2018 09:16:00 -0500 Received: from mail-pl1-f194.google.com ([209.85.214.194]:44669 "EHLO mail-pl1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726779AbeLDOPq (ORCPT ); Tue, 4 Dec 2018 09:15:46 -0500 Received: by mail-pl1-f194.google.com with SMTP id k8so8354749pls.11 for ; Tue, 04 Dec 2018 06:15:46 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=g.ncu.edu.tw; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HzGxbD6sosRISQ+eh8syC+Tz0nZncrfSJXVFQ0T2nG8=; b=bYQ9gw32+zrc0bROpFbTjCjXOCC/NIP9j1GxOR+TY5jeqopAsek1xWhCGqmjtzIwmX 6jr2GG5TpkWwVSfGuHz2ewCuIsB0LMdCSbY3r7+RkmW8BhxnAbcV3RcTzoUSM2Ws8azp qeAHM0QSZS2IBk32Bp1C8MGBkTrSqrUhkVmzw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HzGxbD6sosRISQ+eh8syC+Tz0nZncrfSJXVFQ0T2nG8=; b=Evk0bYEbW2R6aKkuXZhwllZDl6XF0Y3ywTtOVEVXlCuoU1Mgo+vAP/2sU9m5Pq9/1I 3zeIo3xJIyqf5yT0lGgLwd8W96QbQEfhC9cSWcWGnP3YHKB6um+69mq+Om1KQ1AuYGUI fKfjKnVHZKy1IdfWsnchmDZY9BgNMllsadJh7hQCQcJqE7JbtFW2KkgO2uzZdQBNHzcf Q9li6RdwEnEvsytq3b05fe080KxUb871hlRlMZiyT6GdZ70iqQwFhZcVdUcVbCcracCh ABOyy5EnPaRE0LLLuH2OXrCibORFMC2QZ1aIL7ur+JKpnUzDHE++WBLQh63LdJqWyo30 Jk0A== X-Gm-Message-State: AA+aEWb5rSH3IdYrPmLNAAc9My5Y4Zwyv1erJpFks76XMWo9NHT4Fluq 1IIrx3MaLrmYYR1HyCW9IzSzqQ== X-Google-Smtp-Source: AFSGD/XOHMF1t5neI3N7YV/WT7PHO2q3ESDR4HSoqspPkTaIuLFH5c1PesUQf4GIlp4lmKY98PB49w== X-Received: by 2002:a17:902:848d:: with SMTP id c13mr20356290plo.257.1543932946091; Tue, 04 Dec 2018 06:15:46 -0800 (PST) Received: from starnight.local ([150.116.248.145]) by smtp.gmail.com with ESMTPSA id n66sm36975863pfk.19.2018.12.04.06.15.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 04 Dec 2018 06:15:45 -0800 (PST) From: Jian-Hong Pan To: =?utf-8?q?Andreas_F=C3=A4rber?= , "David S . Miller" Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Marcel Holtmann , Dollar Chen , Ken Yu , linux-wpan@vger.kernel.org, Stefan Schmidt , Jian-Hong Pan Subject: [PATCH V4 6/6] net: lorawan: List LORAWAN in menuconfig Date: Tue, 4 Dec 2018 22:13:43 +0800 Message-Id: <20181204141341.4353-7-starnight@g.ncu.edu.tw> X-Mailer: git-send-email 2.19.2 In-Reply-To: References: MIME-Version: 1.0 Sender: linux-wpan-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wpan@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP List LORAWAN and MACLORAWAN in menuconfig and make they can be built. Signed-off-by: Jian-Hong Pan --- V2: - Split the LoRaWAN class module patch in V1 into LoRaWAN socket and LoRaWAN Soft MAC modules net/Kconfig | 2 ++ net/Makefile | 2 ++ 2 files changed, 4 insertions(+) diff --git a/net/Kconfig b/net/Kconfig index cf2e651ee31d..03b3ff306778 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -224,6 +224,8 @@ source "net/6lowpan/Kconfig" source "net/ieee802154/Kconfig" source "net/mac802154/Kconfig" source "net/lora/Kconfig" +source "net/lorawan/Kconfig" +source "net/maclorawan/Kconfig" source "net/sched/Kconfig" source "net/dcb/Kconfig" source "net/dns_resolver/Kconfig" diff --git a/net/Makefile b/net/Makefile index e80b84313851..9d5515965a8f 100644 --- a/net/Makefile +++ b/net/Makefile @@ -63,6 +63,8 @@ obj-$(CONFIG_6LOWPAN) += 6lowpan/ obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ obj-$(CONFIG_LORA) += lora/ +obj-$(CONFIG_LORAWAN) += lorawan/ +obj-$(CONFIG_MACLORAWAN) += maclorawan/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o