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