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_MUTEX(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 bool suspended; 45 46 struct list_head list; 47 struct list_head list_ifup; 48 }; 49 50 static int fakelb_hw_ed(struct ieee802154_hw *hw, u8 *level) 51 { 52 BUG_ON(!level); 53 *level = 0xbe; 54 55 return 0; 56 } 57 58 static int 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 int fakelb_hw_xmit(struct ieee802154_hw *hw, struct sk_buff *skb) 70 { 71 struct fakelb_phy *current_phy = hw->priv, *phy; 72 73 read_lock_bh(&fakelb_ifup_phys_lock); 74 WARN_ON(current_phy->suspended); 75 list_for_each_entry(phy, &fakelb_ifup_phys, list_ifup) { 76 if (current_phy == phy) 77 continue; 78 79 if (current_phy->page == phy->page && 80 current_phy->channel == phy->channel) { 81 struct sk_buff *newskb = pskb_copy(skb, GFP_ATOMIC); 82 83 if (newskb) 84 ieee802154_rx_irqsafe(phy->hw, newskb, 0xcc); 85 } 86 } 87 read_unlock_bh(&fakelb_ifup_phys_lock); 88 89 ieee802154_xmit_complete(hw, skb, false); 90 return 0; 91 } 92 93 static int fakelb_hw_start(struct ieee802154_hw *hw) 94 { 95 struct fakelb_phy *phy = hw->priv; 96 97 write_lock_bh(&fakelb_ifup_phys_lock); 98 phy->suspended = false; 99 list_add(&phy->list_ifup, &fakelb_ifup_phys); 100 write_unlock_bh(&fakelb_ifup_phys_lock); 101 102 return 0; 103 } 104 105 static void fakelb_hw_stop(struct ieee802154_hw *hw) 106 { 107 struct fakelb_phy *phy = hw->priv; 108 109 write_lock_bh(&fakelb_ifup_phys_lock); 110 phy->suspended = true; 111 list_del(&phy->list_ifup); 112 write_unlock_bh(&fakelb_ifup_phys_lock); 113 } 114 115 static int 116 fakelb_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on) 117 { 118 return 0; 119 } 120 121 static const struct ieee802154_ops fakelb_ops = { 122 .owner = THIS_MODULE, 123 .xmit_async = fakelb_hw_xmit, 124 .ed = fakelb_hw_ed, 125 .set_channel = fakelb_hw_channel, 126 .start = fakelb_hw_start, 127 .stop = fakelb_hw_stop, 128 .set_promiscuous_mode = fakelb_set_promiscuous_mode, 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) 136 { 137 struct ieee802154_hw *hw; 138 struct fakelb_phy *phy; 139 int err; 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 ieee802154_random_extended_addr(&hw->phy->perm_extended_addr); 180 /* fake phy channel 13 as default */ 181 hw->phy->current_channel = 13; 182 phy->channel = hw->phy->current_channel; 183 184 hw->flags = IEEE802154_HW_PROMISCUOUS; 185 hw->parent = dev; 186 187 err = ieee802154_register_hw(hw); 188 if (err) 189 goto err_reg; 190 191 mutex_lock(&fakelb_phys_lock); 192 list_add_tail(&phy->list, &fakelb_phys); 193 mutex_unlock(&fakelb_phys_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 list_del(&phy->list); 205 206 ieee802154_unregister_hw(phy->hw); 207 ieee802154_free_hw(phy->hw); 208 } 209 210 static int fakelb_probe(struct platform_device *pdev) 211 { 212 struct fakelb_phy *phy, *tmp; 213 int err, i; 214 215 for (i = 0; i < numlbs; i++) { 216 err = fakelb_add_one(&pdev->dev); 217 if (err < 0) 218 goto err_slave; 219 } 220 221 dev_info(&pdev->dev, "added %i fake ieee802154 hardware devices\n", numlbs); 222 return 0; 223 224 err_slave: 225 mutex_lock(&fakelb_phys_lock); 226 list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) 227 fakelb_del(phy); 228 mutex_unlock(&fakelb_phys_lock); 229 return err; 230 } 231 232 static int fakelb_remove(struct platform_device *pdev) 233 { 234 struct fakelb_phy *phy, *tmp; 235 236 mutex_lock(&fakelb_phys_lock); 237 list_for_each_entry_safe(phy, tmp, &fakelb_phys, list) 238 fakelb_del(phy); 239 mutex_unlock(&fakelb_phys_lock); 240 return 0; 241 } 242 243 static struct platform_device *ieee802154fake_dev; 244 245 static struct platform_driver ieee802154fake_driver = { 246 .probe = fakelb_probe, 247 .remove = fakelb_remove, 248 .driver = { 249 .name = "ieee802154fakelb", 250 }, 251 }; 252 253 static __init int fakelb_init_module(void) 254 { 255 ieee802154fake_dev = platform_device_register_simple( 256 "ieee802154fakelb", -1, NULL, 0); 257 return platform_driver_register(&ieee802154fake_driver); 258 } 259 260 static __exit void fake_remove_module(void) 261 { 262 platform_driver_unregister(&ieee802154fake_driver); 263 platform_device_unregister(ieee802154fake_dev); 264 } 265 266 module_init(fakelb_init_module); 267 module_exit(fake_remove_module); 268 MODULE_LICENSE("GPL"); 269