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