1/* 2 * Sample driver for HardMAC IEEE 802.15.4 devices 3 * 4 * Copyright (C) 2009 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 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Written by: 20 * Dmitry Eremin-Solenikov <dmitry.baryshkov@siemens.com> 21 */ 22#include <linux/kernel.h> 23#include <linux/module.h> 24#include <linux/platform_device.h> 25#include <linux/netdevice.h> 26#include <linux/skbuff.h> 27#include <linux/if_arp.h> 28 29#include <net/af_ieee802154.h> 30#include <net/ieee802154_netdev.h> 31#include <net/ieee802154.h> 32#include <net/nl802154.h> 33#include <net/wpan-phy.h> 34 35struct fakehard_priv { 36 struct wpan_phy *phy; 37}; 38 39static struct wpan_phy *fake_to_phy(const struct net_device *dev) 40{ 41 struct fakehard_priv *priv = netdev_priv(dev); 42 return priv->phy; 43} 44 45/** 46 * fake_get_phy - Return a phy corresponding to this device. 47 * @dev: The network device for which to return the wan-phy object 48 * 49 * This function returns a wpan-phy object corresponding to the passed 50 * network device. Reference counter for wpan-phy object is incremented, 51 * so when the wpan-phy isn't necessary, you should drop the reference 52 * via @wpan_phy_put() call. 53 */ 54static struct wpan_phy *fake_get_phy(const struct net_device *dev) 55{ 56 struct wpan_phy *phy = fake_to_phy(dev); 57 return to_phy(get_device(&phy->dev)); 58} 59 60/** 61 * fake_get_pan_id - Retrieve the PAN ID of the device. 62 * @dev: The network device to retrieve the PAN of. 63 * 64 * Return the ID of the PAN from the PIB. 65 */ 66static u16 fake_get_pan_id(const struct net_device *dev) 67{ 68 BUG_ON(dev->type != ARPHRD_IEEE802154); 69 70 return 0xeba1; 71} 72 73/** 74 * fake_get_short_addr - Retrieve the short address of the device. 75 * @dev: The network device to retrieve the short address of. 76 * 77 * Returns the IEEE 802.15.4 short-form address cached for this 78 * device. If the device has not yet had a short address assigned 79 * then this should return 0xFFFF to indicate a lack of association. 80 */ 81static u16 fake_get_short_addr(const struct net_device *dev) 82{ 83 BUG_ON(dev->type != ARPHRD_IEEE802154); 84 85 return 0x1; 86} 87 88/** 89 * fake_get_dsn - Retrieve the DSN of the device. 90 * @dev: The network device to retrieve the DSN for. 91 * 92 * Returns the IEEE 802.15.4 DSN for the network device. 93 * The DSN is the sequence number which will be added to each 94 * packet or MAC command frame by the MAC during transmission. 95 * 96 * DSN means 'Data Sequence Number'. 97 * 98 * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 99 * document. 100 */ 101static u8 fake_get_dsn(const struct net_device *dev) 102{ 103 BUG_ON(dev->type != ARPHRD_IEEE802154); 104 105 return 0x00; /* DSN are implemented in HW, so return just 0 */ 106} 107 108/** 109 * fake_get_bsn - Retrieve the BSN of the device. 110 * @dev: The network device to retrieve the BSN for. 111 * 112 * Returns the IEEE 802.15.4 BSN for the network device. 113 * The BSN is the sequence number which will be added to each 114 * beacon frame sent by the MAC. 115 * 116 * BSN means 'Beacon Sequence Number'. 117 * 118 * Note: This is in section 7.2.1.2 of the IEEE 802.15.4-2006 119 * document. 120 */ 121static u8 fake_get_bsn(const struct net_device *dev) 122{ 123 BUG_ON(dev->type != ARPHRD_IEEE802154); 124 125 return 0x00; /* BSN are implemented in HW, so return just 0 */ 126} 127 128/** 129 * fake_assoc_req - Make an association request to the HW. 130 * @dev: The network device which we are associating to a network. 131 * @addr: The coordinator with which we wish to associate. 132 * @channel: The channel on which to associate. 133 * @cap: The capability information field to use in the association. 134 * 135 * Start an association with a coordinator. The coordinator's address 136 * and PAN ID can be found in @addr. 137 * 138 * Note: This is in section 7.3.1 and 7.5.3.1 of the IEEE 139 * 802.15.4-2006 document. 140 */ 141static int fake_assoc_req(struct net_device *dev, 142 struct ieee802154_addr *addr, u8 channel, u8 page, u8 cap) 143{ 144 struct wpan_phy *phy = fake_to_phy(dev); 145 146 mutex_lock(&phy->pib_lock); 147 phy->current_channel = channel; 148 phy->current_page = page; 149 mutex_unlock(&phy->pib_lock); 150 151 /* We simply emulate it here */ 152 return ieee802154_nl_assoc_confirm(dev, fake_get_short_addr(dev), 153 IEEE802154_SUCCESS); 154} 155 156/** 157 * fake_assoc_resp - Send an association response to a device. 158 * @dev: The network device on which to send the response. 159 * @addr: The address of the device to respond to. 160 * @short_addr: The assigned short address for the device (if any). 161 * @status: The result of the association request. 162 * 163 * Queue the association response of the coordinator to another 164 * device's attempt to associate with the network which we 165 * coordinate. This is then added to the indirect-send queue to be 166 * transmitted to the end device when it polls for data. 167 * 168 * Note: This is in section 7.3.2 and 7.5.3.1 of the IEEE 169 * 802.15.4-2006 document. 170 */ 171static int fake_assoc_resp(struct net_device *dev, 172 struct ieee802154_addr *addr, u16 short_addr, u8 status) 173{ 174 return 0; 175} 176 177/** 178 * fake_disassoc_req - Disassociate a device from a network. 179 * @dev: The network device on which we're disassociating a device. 180 * @addr: The device to disassociate from the network. 181 * @reason: The reason to give to the device for being disassociated. 182 * 183 * This sends a disassociation notification to the device being 184 * disassociated from the network. 185 * 186 * Note: This is in section 7.5.3.2 of the IEEE 802.15.4-2006 187 * document, with the reason described in 7.3.3.2. 188 */ 189static int fake_disassoc_req(struct net_device *dev, 190 struct ieee802154_addr *addr, u8 reason) 191{ 192 return ieee802154_nl_disassoc_confirm(dev, IEEE802154_SUCCESS); 193} 194 195/** 196 * fake_start_req - Start an IEEE 802.15.4 PAN. 197 * @dev: The network device on which to start the PAN. 198 * @addr: The coordinator address to use when starting the PAN. 199 * @channel: The channel on which to start the PAN. 200 * @bcn_ord: Beacon order. 201 * @sf_ord: Superframe order. 202 * @pan_coord: Whether or not we are the PAN coordinator or just 203 * requesting a realignment perhaps? 204 * @blx: Battery Life Extension feature bitfield. 205 * @coord_realign: Something to realign something else. 206 * 207 * If pan_coord is non-zero then this starts a network with the 208 * provided parameters, otherwise it attempts a coordinator 209 * realignment of the stated network instead. 210 * 211 * Note: This is in section 7.5.2.3 of the IEEE 802.15.4-2006 212 * document, with 7.3.8 describing coordinator realignment. 213 */ 214static int fake_start_req(struct net_device *dev, struct ieee802154_addr *addr, 215 u8 channel, u8 page, 216 u8 bcn_ord, u8 sf_ord, u8 pan_coord, u8 blx, 217 u8 coord_realign) 218{ 219 struct wpan_phy *phy = fake_to_phy(dev); 220 221 mutex_lock(&phy->pib_lock); 222 phy->current_channel = channel; 223 phy->current_page = page; 224 mutex_unlock(&phy->pib_lock); 225 226 /* We don't emulate beacons here at all, so START should fail */ 227 ieee802154_nl_start_confirm(dev, IEEE802154_INVALID_PARAMETER); 228 return 0; 229} 230 231/** 232 * fake_scan_req - Start a channel scan. 233 * @dev: The network device on which to perform a channel scan. 234 * @type: The type of scan to perform. 235 * @channels: The channel bitmask to scan. 236 * @duration: How long to spend on each channel. 237 * 238 * This starts either a passive (energy) scan or an active (PAN) scan 239 * on the channels indicated in the @channels bitmask. The duration of 240 * the scan is measured in terms of superframe duration. Specifically, 241 * the scan will spend aBaseSuperFrameDuration * ((2^n) + 1) on each 242 * channel. 243 * 244 * Note: This is in section 7.5.2.1 of the IEEE 802.15.4-2006 document. 245 */ 246static int fake_scan_req(struct net_device *dev, u8 type, u32 channels, 247 u8 page, u8 duration) 248{ 249 u8 edl[27] = {}; 250 return ieee802154_nl_scan_confirm(dev, IEEE802154_SUCCESS, type, 251 channels, page, 252 type == IEEE802154_MAC_SCAN_ED ? edl : NULL); 253} 254 255static struct ieee802154_mlme_ops fake_mlme = { 256 .assoc_req = fake_assoc_req, 257 .assoc_resp = fake_assoc_resp, 258 .disassoc_req = fake_disassoc_req, 259 .start_req = fake_start_req, 260 .scan_req = fake_scan_req, 261 262 .get_phy = fake_get_phy, 263 264 .get_pan_id = fake_get_pan_id, 265 .get_short_addr = fake_get_short_addr, 266 .get_dsn = fake_get_dsn, 267 .get_bsn = fake_get_bsn, 268}; 269 270static int ieee802154_fake_open(struct net_device *dev) 271{ 272 netif_start_queue(dev); 273 return 0; 274} 275 276static int ieee802154_fake_close(struct net_device *dev) 277{ 278 netif_stop_queue(dev); 279 return 0; 280} 281 282static netdev_tx_t ieee802154_fake_xmit(struct sk_buff *skb, 283 struct net_device *dev) 284{ 285 dev->stats.tx_packets++; 286 dev->stats.tx_bytes += skb->len; 287 288 289 dev_kfree_skb(skb); 290 return NETDEV_TX_OK; 291} 292 293 294static int ieee802154_fake_ioctl(struct net_device *dev, struct ifreq *ifr, 295 int cmd) 296{ 297 struct sockaddr_ieee802154 *sa = 298 (struct sockaddr_ieee802154 *)&ifr->ifr_addr; 299 u16 pan_id, short_addr; 300 301 switch (cmd) { 302 case SIOCGIFADDR: 303 pan_id = fake_get_pan_id(dev); 304 short_addr = fake_get_short_addr(dev); 305 if (pan_id == IEEE802154_PANID_BROADCAST || 306 short_addr == IEEE802154_ADDR_BROADCAST) 307 return -EADDRNOTAVAIL; 308 309 sa->family = AF_IEEE802154; 310 sa->addr.addr_type = IEEE802154_ADDR_SHORT; 311 sa->addr.pan_id = pan_id; 312 sa->addr.short_addr = short_addr; 313 return 0; 314 } 315 return -ENOIOCTLCMD; 316} 317 318static int ieee802154_fake_mac_addr(struct net_device *dev, void *p) 319{ 320 return -EBUSY; /* HW address is built into the device */ 321} 322 323static const struct net_device_ops fake_ops = { 324 .ndo_open = ieee802154_fake_open, 325 .ndo_stop = ieee802154_fake_close, 326 .ndo_start_xmit = ieee802154_fake_xmit, 327 .ndo_do_ioctl = ieee802154_fake_ioctl, 328 .ndo_set_mac_address = ieee802154_fake_mac_addr, 329}; 330 331static void ieee802154_fake_destruct(struct net_device *dev) 332{ 333 struct wpan_phy *phy = fake_to_phy(dev); 334 335 wpan_phy_unregister(phy); 336 free_netdev(dev); 337 wpan_phy_free(phy); 338} 339 340static void ieee802154_fake_setup(struct net_device *dev) 341{ 342 dev->addr_len = IEEE802154_ADDR_LEN; 343 memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN); 344 dev->features = NETIF_F_NO_CSUM; 345 dev->needed_tailroom = 2; /* FCS */ 346 dev->mtu = 127; 347 dev->tx_queue_len = 10; 348 dev->type = ARPHRD_IEEE802154; 349 dev->flags = IFF_NOARP | IFF_BROADCAST; 350 dev->watchdog_timeo = 0; 351 dev->destructor = ieee802154_fake_destruct; 352} 353 354 355static int __devinit ieee802154fake_probe(struct platform_device *pdev) 356{ 357 struct net_device *dev; 358 struct fakehard_priv *priv; 359 struct wpan_phy *phy = wpan_phy_alloc(0); 360 int err; 361 362 if (!phy) 363 return -ENOMEM; 364 365 dev = alloc_netdev(sizeof(struct fakehard_priv), "hardwpan%d", ieee802154_fake_setup); 366 if (!dev) { 367 wpan_phy_free(phy); 368 return -ENOMEM; 369 } 370 371 phy->dev.platform_data = dev; 372 373 memcpy(dev->dev_addr, "\xba\xbe\xca\xfe\xde\xad\xbe\xef", 374 dev->addr_len); 375 memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); 376 377 /* 378 * For now we'd like to emulate 2.4 GHz-only device, 379 * both O-QPSK and CSS 380 */ 381 /* 2.4 GHz O-QPSK 802.15.4-2003 */ 382 phy->channels_supported[0] |= 0x7FFF800; 383 /* 2.4 GHz CSS 802.15.4a-2007 */ 384 phy->channels_supported[3] |= 0x3fff; 385 386 phy->transmit_power = 0xbf; 387 388 dev->netdev_ops = &fake_ops; 389 dev->ml_priv = &fake_mlme; 390 391 priv = netdev_priv(dev); 392 priv->phy = phy; 393 394 /* 395 * If the name is a format string the caller wants us to do a 396 * name allocation. 397 */ 398 if (strchr(dev->name, '%')) { 399 err = dev_alloc_name(dev, dev->name); 400 if (err < 0) 401 goto out; 402 } 403 404 wpan_phy_set_dev(phy, &pdev->dev); 405 SET_NETDEV_DEV(dev, &phy->dev); 406 407 platform_set_drvdata(pdev, dev); 408 409 err = wpan_phy_register(phy); 410 if (err) 411 goto out; 412 413 err = register_netdev(dev); 414 if (err < 0) 415 goto out; 416 417 dev_info(&pdev->dev, "Added ieee802154 HardMAC hardware\n"); 418 return 0; 419 420out: 421 unregister_netdev(dev); 422 return err; 423} 424 425static int __devexit ieee802154fake_remove(struct platform_device *pdev) 426{ 427 struct net_device *dev = platform_get_drvdata(pdev); 428 unregister_netdev(dev); 429 return 0; 430} 431 432static struct platform_device *ieee802154fake_dev; 433 434static struct platform_driver ieee802154fake_driver = { 435 .probe = ieee802154fake_probe, 436 .remove = __devexit_p(ieee802154fake_remove), 437 .driver = { 438 .name = "ieee802154hardmac", 439 .owner = THIS_MODULE, 440 }, 441}; 442 443static __init int fake_init(void) 444{ 445 ieee802154fake_dev = platform_device_register_simple( 446 "ieee802154hardmac", -1, NULL, 0); 447 return platform_driver_register(&ieee802154fake_driver); 448} 449 450static __exit void fake_exit(void) 451{ 452 platform_driver_unregister(&ieee802154fake_driver); 453 platform_device_unregister(ieee802154fake_dev); 454} 455 456module_init(fake_init); 457module_exit(fake_exit); 458MODULE_LICENSE("GPL"); 459