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 30 static int numlbs = 2; 31 32 struct fakelb_phy { 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 42 struct fakelb_priv { 43 struct list_head list; 44 rwlock_t lock; 45 }; 46 47 static int 48 fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) 49 { 50 BUG_ON(!level); 51 *level = 0xbe; 52 53 return 0; 54 } 55 56 static int 57 fakelb_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 64 static void 65 fakelb_hw_deliver(struct fakelb_phy *phy, struct sk_buff *skb) 66 { 67 struct sk_buff *newskb; 68 69 spin_lock(&phy->lock); 70 if (phy->working) { 71 newskb = pskb_copy(skb, GFP_ATOMIC); 72 if (newskb) 73 ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); 74 } 75 spin_unlock(&phy->lock); 76 } 77 78 static int 79 fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) 80 { 81 struct fakelb_phy *current_phy = hw->priv; 82 struct fakelb_priv *fake = current_phy->fake; 83 84 read_lock_bh(&fake->lock); 85 if (current_phy->list.next == current_phy->list.prev) { 86 /* we are the only one device */ 87 fakelb_hw_deliver(current_phy, skb); 88 } else { 89 struct fakelb_phy *phy; 90 91 list_for_each_entry(phy, ¤t_phy->fake->list, list) { 92 if (current_phy != phy && 93 (phy->hw->phy->current_channel == 94 current_phy->hw->phy->current_channel)) 95 fakelb_hw_deliver(phy, skb); 96 } 97 } 98 read_unlock_bh(&fake->lock); 99 100 return 0; 101 } 102 103 static int 104 fakelb_hw_start(struct ieee802154_hw *hw) { 105 struct fakelb_phy *phy = hw->priv; 106 int ret = 0; 107 108 spin_lock(&phy->lock); 109 if (phy->working) 110 ret = -EBUSY; 111 else 112 phy->working = 1; 113 spin_unlock(&phy->lock); 114 115 return ret; 116 } 117 118 static void 119 fakelb_hw_stop(struct ieee802154_hw *hw) { 120 struct fakelb_phy *phy = hw->priv; 121 122 spin_lock(&phy->lock); 123 phy->working = 0; 124 spin_unlock(&phy->lock); 125 } 126 127 static const struct ieee802154_ops fakelb_ops = { 128 .owner = THIS_MODULE, 129 .xmit_sync = fakelb_hw_xmit, 130 .ed = fakelb_hw_ed, 131 .set_channel = fakelb_hw_channel, 132 .start = fakelb_hw_start, 133 .stop = fakelb_hw_stop, 134 }; 135 136 /* Number of dummy devices to be set up by this module. */ 137 module_param(numlbs, int, 0); 138 MODULE_PARM_DESC(numlbs, " number of pseudo devices"); 139 140 static int fakelb_add_one(struct device *dev, struct fakelb_priv *fake) 141 { 142 struct fakelb_phy *phy; 143 int err; 144 struct ieee802154_hw *hw; 145 146 hw = ieee802154_alloc_hw(sizeof(*phy), &fakelb_ops); 147 if (!hw) 148 return -ENOMEM; 149 150 phy = hw->priv; 151 phy->hw = hw; 152 153 /* 868 MHz BPSK 802.15.4-2003 */ 154 hw->phy->supported.channels[0] |= 1; 155 /* 915 MHz BPSK 802.15.4-2003 */ 156 hw->phy->supported.channels[0] |= 0x7fe; 157 /* 2.4 GHz O-QPSK 802.15.4-2003 */ 158 hw->phy->supported.channels[0] |= 0x7FFF800; 159 /* 868 MHz ASK 802.15.4-2006 */ 160 hw->phy->supported.channels[1] |= 1; 161 /* 915 MHz ASK 802.15.4-2006 */ 162 hw->phy->supported.channels[1] |= 0x7fe; 163 /* 868 MHz O-QPSK 802.15.4-2006 */ 164 hw->phy->supported.channels[2] |= 1; 165 /* 915 MHz O-QPSK 802.15.4-2006 */ 166 hw->phy->supported.channels[2] |= 0x7fe; 167 /* 2.4 GHz CSS 802.15.4a-2007 */ 168 hw->phy->supported.channels[3] |= 0x3fff; 169 /* UWB Sub-gigahertz 802.15.4a-2007 */ 170 hw->phy->supported.channels[4] |= 1; 171 /* UWB Low band 802.15.4a-2007 */ 172 hw->phy->supported.channels[4] |= 0x1e; 173 /* UWB High band 802.15.4a-2007 */ 174 hw->phy->supported.channels[4] |= 0xffe0; 175 /* 750 MHz O-QPSK 802.15.4c-2009 */ 176 hw->phy->supported.channels[5] |= 0xf; 177 /* 750 MHz MPSK 802.15.4c-2009 */ 178 hw->phy->supported.channels[5] |= 0xf0; 179 /* 950 MHz BPSK 802.15.4d-2009 */ 180 hw->phy->supported.channels[6] |= 0x3ff; 181 /* 950 MHz GFSK 802.15.4d-2009 */ 182 hw->phy->supported.channels[6] |= 0x3ffc00; 183 184 INIT_LIST_HEAD(&phy->list); 185 phy->fake = fake; 186 187 spin_lock_init(&phy->lock); 188 189 hw->parent = dev; 190 191 err = ieee802154_register_hw(hw); 192 if (err) 193 goto err_reg; 194 195 write_lock_bh(&fake->lock); 196 list_add_tail(&phy->list, &fake->list); 197 write_unlock_bh(&fake->lock); 198 199 return 0; 200 201 err_reg: 202 ieee802154_free_hw(phy->hw); 203 return err; 204 } 205 206 static void fakelb_del(struct fakelb_phy *phy) 207 { 208 write_lock_bh(&phy->fake->lock); 209 list_del(&phy->list); 210 write_unlock_bh(&phy->fake->lock); 211 212 ieee802154_unregister_hw(phy->hw); 213 ieee802154_free_hw(phy->hw); 214 } 215 216 static int fakelb_probe(struct platform_device *pdev) 217 { 218 struct fakelb_priv *priv; 219 struct fakelb_phy *phy, *tmp; 220 int err = -ENOMEM; 221 int i; 222 223 priv = devm_kzalloc(&pdev->dev, sizeof(struct fakelb_priv), 224 GFP_KERNEL); 225 if (!priv) 226 goto err_alloc; 227 228 INIT_LIST_HEAD(&priv->list); 229 rwlock_init(&priv->lock); 230 231 for (i = 0; i < numlbs; i++) { 232 err = fakelb_add_one(&pdev->dev, priv); 233 if (err < 0) 234 goto err_slave; 235 } 236 237 platform_set_drvdata(pdev, priv); 238 dev_info(&pdev->dev, "added ieee802154 hardware\n"); 239 return 0; 240 241 err_slave: 242 list_for_each_entry_safe(phy, tmp, &priv->list, list) 243 fakelb_del(phy); 244 err_alloc: 245 return err; 246 } 247 248 static int fakelb_remove(struct platform_device *pdev) 249 { 250 struct fakelb_priv *priv = platform_get_drvdata(pdev); 251 struct fakelb_phy *phy, *temp; 252 253 list_for_each_entry_safe(phy, temp, &priv->list, list) 254 fakelb_del(phy); 255 256 return 0; 257 } 258 259 static struct platform_device *ieee802154fake_dev; 260 261 static struct platform_driver ieee802154fake_driver = { 262 .probe = fakelb_probe, 263 .remove = fakelb_remove, 264 .driver = { 265 .name = "ieee802154fakelb", 266 }, 267 }; 268 269 static __init int fakelb_init_module(void) 270 { 271 ieee802154fake_dev = platform_device_register_simple( 272 "ieee802154fakelb", -1, NULL, 0); 273 return platform_driver_register(&ieee802154fake_driver); 274 } 275 276 static __exit void fake_remove_module(void) 277 { 278 platform_driver_unregister(&ieee802154fake_driver); 279 platform_device_unregister(ieee802154fake_dev); 280 } 281 282 module_init(fakelb_init_module); 283 module_exit(fake_remove_module); 284 MODULE_LICENSE("GPL"); 285