From: Alexander Smirnov <alexander@Lenovo.(none)> Add support for loopback driver. It's very useful tool for testing and development upper IEEE 802.15.4 layer.
Signed-off-by: Alexander Smirnov <alex.bluesman.smir...@gmail.com> --- drivers/ieee802154/Kconfig | 8 + drivers/ieee802154/Makefile | 1 + drivers/ieee802154/fakelb.c | 296 +++++++++++++++++++++++++++++++++++++++++++ include/net/mac802154.h | 4 + 4 files changed, 309 insertions(+), 0 deletions(-) create mode 100644 drivers/ieee802154/fakelb.c diff --git a/drivers/ieee802154/Kconfig b/drivers/ieee802154/Kconfig index 9b9f43a..0e61489 100644 --- a/drivers/ieee802154/Kconfig +++ b/drivers/ieee802154/Kconfig @@ -19,4 +19,12 @@ config IEEE802154_FAKEHARD This driver can also be built as a module. To do so say M here. The module will be called 'fakehard'. +config IEEE802154_FAKELB + depends on IEEE802154_DRIVERS && MAC802154 + tristate "Fake LR-WPAN driver with several interconnected devices" + ---help--- + Say Y here to enable the fake driver that can emulate a net + of several interconnected radio devices. + This driver can also be built as a module. To do so say M here. + The module will be called 'fakelb'. diff --git a/drivers/ieee802154/Makefile b/drivers/ieee802154/Makefile index 800a389..ea784ea 100644 --- a/drivers/ieee802154/Makefile +++ b/drivers/ieee802154/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_IEEE802154_FAKEHARD) += fakehard.o +obj-$(CONFIG_IEEE802154_FAKELB) += fakelb.o diff --git a/drivers/ieee802154/fakelb.c b/drivers/ieee802154/fakelb.c new file mode 100644 index 0000000..f481318 --- /dev/null +++ b/drivers/ieee802154/fakelb.c @@ -0,0 +1,296 @@ +/* + * Loopback IEEE 802.15.4 interface + * + * Copyright 2007-2011 Siemens AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Written by: + * Sergey Lapin <sla...@ossfans.org> + * Dmitry Eremin-Solenikov <dbarysh...@gmail.com> + * Alexander Smirnov <alex.bluesman.smir...@gmail.com> + */ + +#include <linux/module.h> +#include <linux/timer.h> +#include <linux/platform_device.h> +#include <linux/netdevice.h> +#include <linux/spinlock.h> +#include <net/mac802154.h> +#include <net/wpan-phy.h> + +#include <linux/rtnetlink.h> +#include <net/rtnetlink.h> + +struct fakelb_link_priv { + struct ieee802154_dev *dev; + struct list_head list; + struct fakelb_priv *fakelb; + unsigned int working:1; +}; + +struct fakelb_priv { + struct list_head list; + rwlock_t lock; +}; + +static inline struct fakelb_priv *fakelb_priv(struct net_device *dev) +{ + return netdev_priv(dev); +} + +static int +fakelb_hw_ed(struct ieee802154_dev *dev, u8 *level) +{ + pr_debug("(%s)\n", __func__); + + might_sleep(); + BUG_ON(!level); + *level = 0xbe; + + return 0; +} + +static int +fakelb_hw_channel(struct ieee802154_dev *dev, int page, int channel) +{ + pr_debug("(%s): setting channel to %d\n", __func__, channel); + + might_sleep(); + dev->phy->current_page = page; + dev->phy->current_channel = channel; + + return 0; +} + +static void +fakelb_hw_deliver(struct fakelb_link_priv *priv, struct sk_buff *skb) +{ + struct sk_buff *newskb; + + if (!priv->working) + return; + + newskb = pskb_copy(skb, GFP_ATOMIC); + + ieee802154_rx_irqsafe(priv->dev, newskb, 0xcc); +} + +static int +fakelb_hw_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) +{ + struct fakelb_link_priv *priv = dev->priv; + struct fakelb_priv *fake = priv->fakelb; + + might_sleep(); + + read_lock_bh(&fake->lock); + if (priv->list.next == priv->list.prev) { + /* we are the only one device */ + fakelb_hw_deliver(priv, skb); + } else { + struct fakelb_link_priv *dp; + list_for_each_entry(dp, &priv->fakelb->list, list) + if (dp != priv && + dp->dev->phy->current_channel == + priv->dev->phy->current_channel) + fakelb_hw_deliver(dp, skb); + } + read_unlock_bh(&fake->lock); + + return 0; +} + +static int +fakelb_hw_start(struct ieee802154_dev *dev) { + struct fakelb_link_priv *priv = dev->priv; + + if (priv->working) + return -EBUSY; + + priv->working = 1; + + return 0; +} + +static void +fakelb_hw_stop(struct ieee802154_dev *dev) { + struct fakelb_link_priv *priv = dev->priv; + + priv->working = 0; +} + +static struct ieee802154_ops fakelb_ops = { + .owner = THIS_MODULE, + .xmit = fakelb_hw_xmit, + .ed = fakelb_hw_ed, + .set_channel = fakelb_hw_channel, + .start = fakelb_hw_start, + .stop = fakelb_hw_stop, +}; + +static int +fakelb_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct fakelb_link_priv *priv; + struct fakelb_priv *info = fakelb_priv(dev); + struct ieee802154_dev *ieee; + int err; + + ieee = ieee802154_alloc_device(sizeof(*priv), &fakelb_ops); + if (!ieee) + return -ENOMEM; + + priv = ieee->priv; + priv->dev = ieee; + + /* 868 MHz BPSK 802.15.4-2003 */ + ieee->phy->channels_supported[0] |= 1; + /* 915 MHz BPSK 802.15.4-2003 */ + ieee->phy->channels_supported[0] |= 0x7fe; + /* 2.4 GHz O-QPSK 802.15.4-2003 */ + ieee->phy->channels_supported[0] |= 0x7FFF800; + /* 868 MHz ASK 802.15.4-2006 */ + ieee->phy->channels_supported[1] |= 1; + /* 915 MHz ASK 802.15.4-2006 */ + ieee->phy->channels_supported[1] |= 0x7fe; + /* 868 MHz O-QPSK 802.15.4-2006 */ + ieee->phy->channels_supported[2] |= 1; + /* 915 MHz O-QPSK 802.15.4-2006 */ + ieee->phy->channels_supported[2] |= 0x7fe; + /* 2.4 GHz CSS 802.15.4a-2007 */ + ieee->phy->channels_supported[3] |= 0x3fff; + /* UWB Sub-gigahertz 802.15.4a-2007 */ + ieee->phy->channels_supported[4] |= 1; + /* UWB Low band 802.15.4a-2007 */ + ieee->phy->channels_supported[4] |= 0x1e; + /* UWB High band 802.15.4a-2007 */ + ieee->phy->channels_supported[4] |= 0xffe0; + /* 750 MHz O-QPSK 802.15.4c-2009 */ + ieee->phy->channels_supported[5] |= 0xf; + /* 750 MHz MPSK 802.15.4c-2009 */ + ieee->phy->channels_supported[5] |= 0xf0; + /* 950 MHz BPSK 802.15.4d-2009 */ + ieee->phy->channels_supported[6] |= 0x3ff; + /* 950 MHz GFSK 802.15.4d-2009 */ + ieee->phy->channels_supported[6] |= 0x3ffc00; + + INIT_LIST_HEAD(&priv->list); + priv->fakelb = info; + + err = ieee802154_register_device(ieee); + if (err) + goto err_reg; + + write_lock_bh(&info->lock); + list_add_tail(&priv->list, &info->list); + write_unlock_bh(&info->lock); + + return 0; + +err_reg: + ieee802154_free_device(priv->dev); + return err; +} + +static void +fakelb_dellink(struct net_device *dev, struct list_head *head) +{ + struct fakelb_priv *priv = fakelb_priv(dev); + struct fakelb_link_priv *entry, *temp; + + write_lock_bh(&priv->lock); + list_for_each_entry_safe(entry, temp, &priv->list, list) { + list_del(&entry->list); + ieee802154_unregister_device(entry->dev); + ieee802154_free_device(entry->dev); + kfree(entry); + } + write_unlock_bh(&priv->lock); +} + +static void +fakelb_dev_free(struct net_device *dev) +{ + free_netdev(dev); +} + +static void +fakelb_setup(struct net_device *dev) +{ + dev->destructor = fakelb_dev_free; +} + +static struct rtnl_link_ops fakelb_link_ops = { + .kind = "fakelb", + .setup = fakelb_setup, + .priv_size = sizeof(struct fakelb_link_priv), + .newlink = fakelb_newlink, + .dellink = fakelb_dellink, +}; + +static int __init fakelb_init_one(void) +{ + struct net_device *fakelb_dev; + struct fakelb_priv *priv; + int err; + + fakelb_dev = alloc_netdev(sizeof(struct fakelb_priv), "fakelb%d", + fakelb_setup); + if (!fakelb_dev) + return -ENOMEM; + + fakelb_dev->rtnl_link_ops = &fakelb_link_ops; + + err = register_netdevice(fakelb_dev); + if (err < 0) + goto err; + + priv = fakelb_priv(fakelb_dev); + INIT_LIST_HEAD(&priv->list); + rwlock_init(&priv->lock); + + netdev_info(fakelb_dev, "added ieee802154 hardware\n"); + + return 0; +err: + free_netdev(fakelb_dev); + return err; +} + +static int __init fakelb_init_module(void) +{ + int err; + + rtnl_lock(); + + __rtnl_link_register(&fakelb_link_ops); + err = fakelb_init_one(); + if (err) + __rtnl_link_unregister(&fakelb_link_ops); + + rtnl_unlock(); + + return err; +} + +static void __exit fakelb_cleanup_module(void) +{ + rtnl_link_unregister(&fakelb_link_ops); +} + +module_init(fakelb_init_module); +module_exit(fakelb_cleanup_module); +MODULE_LICENSE("GPL"); diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 4e9f042..4854885 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -139,6 +139,10 @@ struct ieee802154_ops { u8 addr[IEEE802154_ADDR_LEN]); }; +struct ieee802154_dev *ieee802154_alloc_device(size_t priv_size, + struct ieee802154_ops *ops); +void ieee802154_free_device(struct ieee802154_dev *dev); + int ieee802154_register_device(struct ieee802154_dev *dev); void ieee802154_unregister_device(struct ieee802154_dev *dev); -- 1.7.0.4 ------------------------------------------------------------------------------ Cloud Computing - Latest Buzzword or a Glimpse of the Future? This paper surveys cloud computing today: What are the benefits? Why are businesses embracing it? What are its payoffs and pitfalls? http://www.accelacomm.com/jaw/sdnl/114/51425149/ _______________________________________________ Linux-zigbee-devel mailing list Linux-zigbee-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel