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