264 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Loopback IEEE 802.15.4 interface4 *5 * Copyright 2007-2012 Siemens AG6 *7 * Written by:8 * Sergey Lapin <slapin@ossfans.org>9 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>10 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>11 */12 13#include <linux/module.h>14#include <linux/timer.h>15#include <linux/platform_device.h>16#include <linux/netdevice.h>17#include <linux/device.h>18#include <linux/spinlock.h>19#include <net/mac802154.h>20#include <net/cfg802154.h>21 22static int numlbs = 2;23 24static LIST_HEAD(fakelb_phys);25static DEFINE_MUTEX(fakelb_phys_lock);26 27static LIST_HEAD(fakelb_ifup_phys);28static DEFINE_RWLOCK(fakelb_ifup_phys_lock);29 30struct fakelb_phy {31 struct ieee802154_hw *hw;32 33 u8 page;34 u8 channel;35 36 bool suspended;37 38 struct list_head list;39 struct list_head list_ifup;40};41 42static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level)43{44 WARN_ON(!level);45 *level = 0xbe;46 47 return 0;48}49 50static int fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel)51{52 struct fakelb_phy *phy = hw->priv;53 54 write_lock_bh(&fakelb_ifup_phys_lock);55 phy->page = page;56 phy->channel = channel;57 write_unlock_bh(&fakelb_ifup_phys_lock);58 return 0;59}60 61static int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb)62{63 struct fakelb_phy *current_phy = hw->priv, *phy;64 65 read_lock_bh(&fakelb_ifup_phys_lock);66 WARN_ON(current_phy->suspended);67 list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) {68 if (current_phy == phy)69 continue;70 71 if (current_phy->page == phy->page &&72 current_phy->channel == phy->channel) {73 struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC);74 75 if (newskb)76 ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc);77 }78 }79 read_unlock_bh(&fakelb_ifup_phys_lock);80 81 ieee802154_xmit_complete(hw, skb, false);82 return 0;83}84 85static int fakelb_hw_start(struct ieee802154_hw *hw)86{87 struct fakelb_phy *phy = hw->priv;88 89 write_lock_bh(&fakelb_ifup_phys_lock);90 phy->suspended = false;91 list_add(&phy->list_ifup, &fakelb_ifup_phys);92 write_unlock_bh(&fakelb_ifup_phys_lock);93 94 return 0;95}96 97static void fakelb_hw_stop(struct ieee802154_hw *hw)98{99 struct fakelb_phy *phy = hw->priv;100 101 write_lock_bh(&fakelb_ifup_phys_lock);102 phy->suspended = true;103 list_del(&phy->list_ifup);104 write_unlock_bh(&fakelb_ifup_phys_lock);105}106 107static int108fakelb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)109{110 return 0;111}112 113static const struct ieee802154_ops fakelb_ops = {114 .owner = THIS_MODULE,115 .xmit_async = fakelb_hw_xmit,116 .ed = fakelb_hw_ed,117 .set_channel = fakelb_hw_channel,118 .start = fakelb_hw_start,119 .stop = fakelb_hw_stop,120 .set_promiscuous_mode = fakelb_set_promiscuous_mode,121};122 123/* Number of dummy devices to be set up by this module. */124module_param(numlbs, int, 0);125MODULE_PARM_DESC(numlbs, " number of pseudo devices");126 127static int fakelb_add_one(struct device *dev)128{129 struct ieee802154_hw *hw;130 struct fakelb_phy *phy;131 int err;132 133 hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops);134 if (!hw)135 return -ENOMEM;136 137 phy = hw->priv;138 phy->hw = hw;139 140 /* 868 MHz BPSK 802.15.4-2003 */141 hw->phy->supported.channels[0] |= 1;142 /* 915 MHz BPSK 802.15.4-2003 */143 hw->phy->supported.channels[0] |= 0x7fe;144 /* 2.4 GHz O-QPSK 802.15.4-2003 */145 hw->phy->supported.channels[0] |= 0x7FFF800;146 /* 868 MHz ASK 802.15.4-2006 */147 hw->phy->supported.channels[1] |= 1;148 /* 915 MHz ASK 802.15.4-2006 */149 hw->phy->supported.channels[1] |= 0x7fe;150 /* 868 MHz O-QPSK 802.15.4-2006 */151 hw->phy->supported.channels[2] |= 1;152 /* 915 MHz O-QPSK 802.15.4-2006 */153 hw->phy->supported.channels[2] |= 0x7fe;154 /* 2.4 GHz CSS 802.15.4a-2007 */155 hw->phy->supported.channels[3] |= 0x3fff;156 /* UWB Sub-gigahertz 802.15.4a-2007 */157 hw->phy->supported.channels[4] |= 1;158 /* UWB Low band 802.15.4a-2007 */159 hw->phy->supported.channels[4] |= 0x1e;160 /* UWB High band 802.15.4a-2007 */161 hw->phy->supported.channels[4] |= 0xffe0;162 /* 750 MHz O-QPSK 802.15.4c-2009 */163 hw->phy->supported.channels[5] |= 0xf;164 /* 750 MHz MPSK 802.15.4c-2009 */165 hw->phy->supported.channels[5] |= 0xf0;166 /* 950 MHz BPSK 802.15.4d-2009 */167 hw->phy->supported.channels[6] |= 0x3ff;168 /* 950 MHz GFSK 802.15.4d-2009 */169 hw->phy->supported.channels[6] |= 0x3ffc00;170 171 ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);172 /* fake phy channel 13 as default */173 hw->phy->current_channel = 13;174 phy->channel = hw->phy->current_channel;175 176 hw->flags = IEEE802154_HW_PROMISCUOUS;177 hw->parent = dev;178 179 err = ieee802154_register_hw(hw);180 if (err)181 goto err_reg;182 183 mutex_lock(&fakelb_phys_lock);184 list_add_tail(&phy->list, &fakelb_phys);185 mutex_unlock(&fakelb_phys_lock);186 187 return 0;188 189err_reg:190 ieee802154_free_hw(phy->hw);191 return err;192}193 194static void fakelb_del(struct fakelb_phy *phy)195{196 list_del(&phy->list);197 198 ieee802154_unregister_hw(phy->hw);199 ieee802154_free_hw(phy->hw);200}201 202static int fakelb_probe(struct platform_device *pdev)203{204 struct fakelb_phy *phy, *tmp;205 int err, i;206 207 for (i = 0; i < numlbs; i++) {208 err = fakelb_add_one(&pdev->dev);209 if (err < 0)210 goto err_slave;211 }212 213 dev_info(&pdev->dev, "added %i fake ieee802154 hardware devices\n", numlbs);214 return 0;215 216err_slave:217 mutex_lock(&fakelb_phys_lock);218 list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)219 fakelb_del(phy);220 mutex_unlock(&fakelb_phys_lock);221 return err;222}223 224static void fakelb_remove(struct platform_device *pdev)225{226 struct fakelb_phy *phy, *tmp;227 228 mutex_lock(&fakelb_phys_lock);229 list_for_each_entry_safe(phy, tmp, &fakelb_phys, list)230 fakelb_del(phy);231 mutex_unlock(&fakelb_phys_lock);232}233 234static struct platform_device *ieee802154fake_dev;235 236static struct platform_driver ieee802154fake_driver = {237 .probe = fakelb_probe,238 .remove_new = fakelb_remove,239 .driver = {240 .name = "ieee802154fakelb",241 },242};243 244static __init int fakelb_init_module(void)245{246 ieee802154fake_dev = platform_device_register_simple(247 "ieee802154fakelb", -1, NULL, 0);248 249 pr_warn("fakelb driver is marked as deprecated, please use mac802154_hwsim!\n");250 251 return platform_driver_register(&ieee802154fake_driver);252}253 254static __exit void fake_remove_module(void)255{256 platform_driver_unregister(&ieee802154fake_driver);257 platform_device_unregister(ieee802154fake_dev);258}259 260module_init(fakelb_init_module);261module_exit(fake_remove_module);262MODULE_DESCRIPTION("IEEE 802.15.4 loopback driver");263MODULE_LICENSE("GPL");264