1/* 2 * Loopback IEEE 802.15.4 interface 3 * 4 * Copyright 2007-2012 Siemens AG 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 8 * as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * Written by: 16 * Sergey Lapin <slapin@ossfans.org> 17 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 18 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 19 */ 20 21#include <linux/module.h> 22#include <linux/timer.h> 23#include <linux/platform_device.h> 24#include <linux/netdevice.h> 25#include <linux/device.h> 26#include <linux/spinlock.h> 27#include <net/mac802154.h> 28#include <net/cfg802154.h> 29 30static int numlbs = 1; 31 32struct fakelb_dev_priv { 33 struct ieee802154_hw *hw; 34 35 struct list_head list; 36 struct fakelb_priv *fake; 37 38 spinlock_t lock; 39 bool working; 40}; 41 42struct fakelb_priv { 43 struct list_head list; 44 rwlock_t lock; 45}; 46 47static int 48fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) 49{ 50 BUG_ON(!level); 51 *level = 0xbe; 52 53 return 0; 54} 55 56static int 57fakelb_hw_channel(struct ieee802154_hw *hw, u8 page, u8 channel) 58{ 59 pr_debug("set channel to %d\n", channel); 60 61 return 0; 62} 63 64static void 65fakelb_hw_deliver(struct fakelb_dev_priv *priv, struct sk_buff *skb) 66{ 67 struct sk_buff *newskb; 68 69 spin_lock(&priv->lock); 70 if (priv->working) { 71 newskb = pskb_copy(skb, GFP_ATOMIC); 72 ieee802154_rx_irqsafe(priv->hw, newskb, 0xcc); 73 } 74 spin_unlock(&priv->lock); 75} 76 77static int 78fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) 79{ 80 struct fakelb_dev_priv *priv = hw->priv; 81 struct fakelb_priv *fake = priv->fake; 82 83 read_lock_bh(&fake->lock); 84 if (priv->list.next == priv->list.prev) { 85 /* we are the only one device */ 86 fakelb_hw_deliver(priv, skb); 87 } else { 88 struct fakelb_dev_priv *dp; 89 list_for_each_entry(dp, &priv->fake->list, list) { 90 if (dp != priv && 91 (dp->hw->phy->current_channel == 92 priv->hw->phy->current_channel)) 93 fakelb_hw_deliver(dp, skb); 94 } 95 } 96 read_unlock_bh(&fake->lock); 97 98 return 0; 99} 100 101static int 102fakelb_hw_start(struct ieee802154_hw *hw) { 103 struct fakelb_dev_priv *priv = hw->priv; 104 int ret = 0; 105 106 spin_lock(&priv->lock); 107 if (priv->working) 108 ret = -EBUSY; 109 else 110 priv->working = 1; 111 spin_unlock(&priv->lock); 112 113 return ret; 114} 115 116static void 117fakelb_hw_stop(struct ieee802154_hw *hw) { 118 struct fakelb_dev_priv *priv = hw->priv; 119 120 spin_lock(&priv->lock); 121 priv->working = 0; 122 spin_unlock(&priv->lock); 123} 124 125static const struct ieee802154_ops fakelb_ops = { 126 .owner = THIS_MODULE, 127 .xmit_sync = fakelb_hw_xmit, 128 .ed = fakelb_hw_ed, 129 .set_channel = fakelb_hw_channel, 130 .start = fakelb_hw_start, 131 .stop = fakelb_hw_stop, 132}; 133 134/* Number of dummy devices to be set up by this module. */ 135module_param(numlbs, int, 0); 136MODULE_PARM_DESC(numlbs, " number of pseudo devices"); 137 138static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) 139{ 140 struct fakelb_dev_priv *priv; 141 int err; 142 struct ieee802154_hw *hw; 143 144 hw = ieee802154_alloc_hw(sizeof(*priv), &fakelb_ops); 145 if (!hw) 146 return -ENOMEM; 147 148 priv = hw->priv; 149 priv->hw = hw; 150 151 /* 868 MHz BPSK 802.15.4-2003 */ 152 hw->phy->channels_supported[0] |= 1; 153 /* 915 MHz BPSK 802.15.4-2003 */ 154 hw->phy->channels_supported[0] |= 0x7fe; 155 /* 2.4 GHz O-QPSK 802.15.4-2003 */ 156 hw->phy->channels_supported[0] |= 0x7FFF800; 157 /* 868 MHz ASK 802.15.4-2006 */ 158 hw->phy->channels_supported[1] |= 1; 159 /* 915 MHz ASK 802.15.4-2006 */ 160 hw->phy->channels_supported[1] |= 0x7fe; 161 /* 868 MHz O-QPSK 802.15.4-2006 */ 162 hw->phy->channels_supported[2] |= 1; 163 /* 915 MHz O-QPSK 802.15.4-2006 */ 164 hw->phy->channels_supported[2] |= 0x7fe; 165 /* 2.4 GHz CSS 802.15.4a-2007 */ 166 hw->phy->channels_supported[3] |= 0x3fff; 167 /* UWB Sub-gigahertz 802.15.4a-2007 */ 168 hw->phy->channels_supported[4] |= 1; 169 /* UWB Low band 802.15.4a-2007 */ 170 hw->phy->channels_supported[4] |= 0x1e; 171 /* UWB High band 802.15.4a-2007 */ 172 hw->phy->channels_supported[4] |= 0xffe0; 173 /* 750 MHz O-QPSK 802.15.4c-2009 */ 174 hw->phy->channels_supported[5] |= 0xf; 175 /* 750 MHz MPSK 802.15.4c-2009 */ 176 hw->phy->channels_supported[5] |= 0xf0; 177 /* 950 MHz BPSK 802.15.4d-2009 */ 178 hw->phy->channels_supported[6] |= 0x3ff; 179 /* 950 MHz GFSK 802.15.4d-2009 */ 180 hw->phy->channels_supported[6] |= 0x3ffc00; 181 182 INIT_LIST_HEAD(&priv->list); 183 priv->fake = fake; 184 185 spin_lock_init(&priv->lock); 186 187 hw->parent = dev; 188 189 err = ieee802154_register_hw(hw); 190 if (err) 191 goto err_reg; 192 193 write_lock_bh(&fake->lock); 194 list_add_tail(&priv->list, &fake->list); 195 write_unlock_bh(&fake->lock); 196 197 return 0; 198 199err_reg: 200 ieee802154_free_hw(priv->hw); 201 return err; 202} 203 204static void fakelb_del(struct fakelb_dev_priv *priv) 205{ 206 write_lock_bh(&priv->fake->lock); 207 list_del(&priv->list); 208 write_unlock_bh(&priv->fake->lock); 209 210 ieee802154_unregister_hw(priv->hw); 211 ieee802154_free_hw(priv->hw); 212} 213 214static int fakelb_probe(struct platform_device *pdev) 215{ 216 struct fakelb_priv *priv; 217 struct fakelb_dev_priv *dp; 218 int err = -ENOMEM; 219 int i; 220 221 priv = devm_kzalloc(&pdev->dev, sizeof(struct fakelb_priv), 222 GFP_KERNEL); 223 if (!priv) 224 goto err_alloc; 225 226 INIT_LIST_HEAD(&priv->list); 227 rwlock_init(&priv->lock); 228 229 for (i = 0; i < numlbs; i++) { 230 err = fakelb_add_one(&pdev->dev, priv); 231 if (err < 0) 232 goto err_slave; 233 } 234 235 platform_set_drvdata(pdev, priv); 236 dev_info(&pdev->dev, "added ieee802154 hardware\n"); 237 return 0; 238 239err_slave: 240 list_for_each_entry(dp, &priv->list, list) 241 fakelb_del(dp); 242err_alloc: 243 return err; 244} 245 246static int fakelb_remove(struct platform_device *pdev) 247{ 248 struct fakelb_priv *priv = platform_get_drvdata(pdev); 249 struct fakelb_dev_priv *dp, *temp; 250 251 list_for_each_entry_safe(dp, temp, &priv->list, list) 252 fakelb_del(dp); 253 254 return 0; 255} 256 257static struct platform_device *ieee802154fake_dev; 258 259static struct platform_driver ieee802154fake_driver = { 260 .probe = fakelb_probe, 261 .remove = fakelb_remove, 262 .driver = { 263 .name = "ieee802154fakelb", 264 }, 265}; 266 267static __init int fakelb_init_module(void) 268{ 269 ieee802154fake_dev = platform_device_register_simple( 270 "ieee802154fakelb", -1, NULL, 0); 271 return platform_driver_register(&ieee802154fake_driver); 272} 273 274static __exit void fake_remove_module(void) 275{ 276 platform_driver_unregister(&ieee802154fake_driver); 277 platform_device_unregister(ieee802154fake_dev); 278} 279 280module_init(fakelb_init_module); 281module_exit(fake_remove_module); 282MODULE_LICENSE("GPL"); 283