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