1 /* 2 * Copyright (C) 2007-2012 Siemens AG 3 * 4 * Written by: 5 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com> 6 * 7 * Based on the code from 'linux-zigbee.sourceforge.net' project. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 11 * as published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/module.h> 21 #include <linux/netdevice.h> 22 23 #include <net/netlink.h> 24 #include <linux/nl802154.h> 25 #include <net/mac802154.h> 26 #include <net/ieee802154_netdev.h> 27 #include <net/route.h> 28 #include <net/cfg802154.h> 29 30 #include "ieee802154_i.h" 31 32 int mac802154_slave_open(struct net_device *dev) 33 { 34 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 35 struct ieee802154_sub_if_data *subif; 36 struct ieee802154_local *local = sdata->local; 37 int res = 0; 38 39 ASSERT_RTNL(); 40 41 if (sdata->type == IEEE802154_DEV_WPAN) { 42 mutex_lock(&sdata->local->iflist_mtx); 43 list_for_each_entry(subif, &sdata->local->interfaces, list) { 44 if (subif != sdata && subif->type == sdata->type && 45 subif->running) { 46 mutex_unlock(&sdata->local->iflist_mtx); 47 return -EBUSY; 48 } 49 } 50 mutex_unlock(&sdata->local->iflist_mtx); 51 } 52 53 mutex_lock(&sdata->local->iflist_mtx); 54 sdata->running = true; 55 mutex_unlock(&sdata->local->iflist_mtx); 56 57 if (local->open_count++ == 0) { 58 res = local->ops->start(&local->hw); 59 WARN_ON(res); 60 if (res) 61 goto err; 62 } 63 64 netif_start_queue(dev); 65 return 0; 66 err: 67 sdata->local->open_count--; 68 69 return res; 70 } 71 72 int mac802154_slave_close(struct net_device *dev) 73 { 74 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 75 struct ieee802154_local *local = sdata->local; 76 77 ASSERT_RTNL(); 78 79 netif_stop_queue(dev); 80 81 mutex_lock(&sdata->local->iflist_mtx); 82 sdata->running = false; 83 mutex_unlock(&sdata->local->iflist_mtx); 84 85 if (!--local->open_count) 86 local->ops->stop(&local->hw); 87 88 return 0; 89 } 90 91 static int 92 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev) 93 { 94 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 95 struct ieee802154_local *local; 96 int err; 97 98 local = wpan_phy_priv(phy); 99 100 sdata->dev = dev; 101 sdata->local = local; 102 103 dev->needed_headroom = local->hw.extra_tx_headroom; 104 105 SET_NETDEV_DEV(dev, &local->phy->dev); 106 107 mutex_lock(&local->iflist_mtx); 108 if (!local->running) { 109 mutex_unlock(&local->iflist_mtx); 110 return -ENODEV; 111 } 112 mutex_unlock(&local->iflist_mtx); 113 114 err = register_netdev(dev); 115 if (err < 0) 116 return err; 117 118 rtnl_lock(); 119 mutex_lock(&local->iflist_mtx); 120 list_add_tail_rcu(&sdata->list, &local->interfaces); 121 mutex_unlock(&local->iflist_mtx); 122 rtnl_unlock(); 123 124 return 0; 125 } 126 127 static void 128 mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) 129 { 130 struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); 131 132 ASSERT_RTNL(); 133 134 BUG_ON(sdata->local->phy != phy); 135 136 mutex_lock(&sdata->local->iflist_mtx); 137 list_del_rcu(&sdata->list); 138 mutex_unlock(&sdata->local->iflist_mtx); 139 140 synchronize_rcu(); 141 unregister_netdevice(sdata->dev); 142 } 143 144 static struct net_device * 145 mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) 146 { 147 struct net_device *dev; 148 int err = -ENOMEM; 149 150 switch (type) { 151 case IEEE802154_DEV_MONITOR: 152 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), 153 name, NET_NAME_UNKNOWN, 154 mac802154_monitor_setup); 155 break; 156 case IEEE802154_DEV_WPAN: 157 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), 158 name, NET_NAME_UNKNOWN, 159 mac802154_wpan_setup); 160 break; 161 default: 162 dev = NULL; 163 err = -EINVAL; 164 break; 165 } 166 if (!dev) 167 goto err; 168 169 err = mac802154_netdev_register(phy, dev); 170 if (err) 171 goto err_free; 172 173 dev_hold(dev); /* we return an incremented device refcount */ 174 return dev; 175 176 err_free: 177 free_netdev(dev); 178 err: 179 return ERR_PTR(err); 180 } 181 182 static int mac802154_set_txpower(struct wpan_phy *phy, int db) 183 { 184 struct ieee802154_local *local = wpan_phy_priv(phy); 185 186 return local->ops->set_txpower(&local->hw, db); 187 } 188 189 static int mac802154_set_lbt(struct wpan_phy *phy, bool on) 190 { 191 struct ieee802154_local *local = wpan_phy_priv(phy); 192 193 return local->ops->set_lbt(&local->hw, on); 194 } 195 196 static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode) 197 { 198 struct ieee802154_local *local = wpan_phy_priv(phy); 199 200 return local->ops->set_cca_mode(&local->hw, mode); 201 } 202 203 static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level) 204 { 205 struct ieee802154_local *local = wpan_phy_priv(phy); 206 207 return local->ops->set_cca_ed_level(&local->hw, level); 208 } 209 210 static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be, 211 u8 max_be, u8 retries) 212 { 213 struct ieee802154_local *local = wpan_phy_priv(phy); 214 215 return local->ops->set_csma_params(&local->hw, min_be, max_be, retries); 216 } 217 218 static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries) 219 { 220 struct ieee802154_local *local = wpan_phy_priv(phy); 221 222 return local->ops->set_frame_retries(&local->hw, retries); 223 } 224 225 static void ieee802154_tasklet_handler(unsigned long data) 226 { 227 struct ieee802154_local *local = (struct ieee802154_local *)data; 228 struct sk_buff *skb; 229 230 while ((skb = skb_dequeue(&local->skb_queue))) { 231 switch (skb->pkt_type) { 232 case IEEE802154_RX_MSG: 233 /* Clear skb->pkt_type in order to not confuse kernel 234 * netstack. 235 */ 236 skb->pkt_type = 0; 237 ieee802154_rx(&local->hw, skb); 238 break; 239 default: 240 WARN(1, "mac802154: Packet is of unknown type %d\n", 241 skb->pkt_type); 242 kfree_skb(skb); 243 break; 244 } 245 } 246 } 247 248 struct ieee802154_hw * 249 ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops) 250 { 251 struct wpan_phy *phy; 252 struct ieee802154_local *local; 253 size_t priv_size; 254 255 if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed || 256 !ops->start || !ops->stop || !ops->set_channel) { 257 pr_err("undefined IEEE802.15.4 device operations\n"); 258 return NULL; 259 } 260 261 /* Ensure 32-byte alignment of our private data and hw private data. 262 * We use the wpan_phy priv data for both our ieee802154_local and for 263 * the driver's private data 264 * 265 * in memory it'll be like this: 266 * 267 * +-------------------------+ 268 * | struct wpan_phy | 269 * +-------------------------+ 270 * | struct ieee802154_local | 271 * +-------------------------+ 272 * | driver's private data | 273 * +-------------------------+ 274 * 275 * Due to ieee802154 layer isn't aware of driver and MAC structures, 276 * so lets align them here. 277 */ 278 279 priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; 280 281 phy = wpan_phy_alloc(priv_size); 282 if (!phy) { 283 pr_err("failure to allocate master IEEE802.15.4 device\n"); 284 return NULL; 285 } 286 287 local = wpan_phy_priv(phy); 288 local->phy = phy; 289 local->hw.phy = local->phy; 290 local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); 291 local->ops = ops; 292 293 INIT_LIST_HEAD(&local->interfaces); 294 mutex_init(&local->iflist_mtx); 295 296 tasklet_init(&local->tasklet, 297 ieee802154_tasklet_handler, 298 (unsigned long)local); 299 300 skb_queue_head_init(&local->skb_queue); 301 302 return &local->hw; 303 } 304 EXPORT_SYMBOL(ieee802154_alloc_hw); 305 306 void ieee802154_free_hw(struct ieee802154_hw *hw) 307 { 308 struct ieee802154_local *local = hw_to_local(hw); 309 310 BUG_ON(!list_empty(&local->interfaces)); 311 312 mutex_destroy(&local->iflist_mtx); 313 314 wpan_phy_free(local->phy); 315 } 316 EXPORT_SYMBOL(ieee802154_free_hw); 317 318 int ieee802154_register_hw(struct ieee802154_hw *hw) 319 { 320 struct ieee802154_local *local = hw_to_local(hw); 321 int rc = -ENOSYS; 322 323 if (hw->flags & IEEE802154_HW_TXPOWER) { 324 if (!local->ops->set_txpower) 325 goto out; 326 327 local->phy->set_txpower = mac802154_set_txpower; 328 } 329 330 if (hw->flags & IEEE802154_HW_LBT) { 331 if (!local->ops->set_lbt) 332 goto out; 333 334 local->phy->set_lbt = mac802154_set_lbt; 335 } 336 337 if (hw->flags & IEEE802154_HW_CCA_MODE) { 338 if (!local->ops->set_cca_mode) 339 goto out; 340 341 local->phy->set_cca_mode = mac802154_set_cca_mode; 342 } 343 344 if (hw->flags & IEEE802154_HW_CCA_ED_LEVEL) { 345 if (!local->ops->set_cca_ed_level) 346 goto out; 347 348 local->phy->set_cca_ed_level = mac802154_set_cca_ed_level; 349 } 350 351 if (hw->flags & IEEE802154_HW_CSMA_PARAMS) { 352 if (!local->ops->set_csma_params) 353 goto out; 354 355 local->phy->set_csma_params = mac802154_set_csma_params; 356 } 357 358 if (hw->flags & IEEE802154_HW_FRAME_RETRIES) { 359 if (!local->ops->set_frame_retries) 360 goto out; 361 362 local->phy->set_frame_retries = mac802154_set_frame_retries; 363 } 364 365 local->workqueue = 366 create_singlethread_workqueue(wpan_phy_name(local->phy)); 367 if (!local->workqueue) { 368 rc = -ENOMEM; 369 goto out; 370 } 371 372 wpan_phy_set_dev(local->phy, local->hw.parent); 373 374 local->phy->add_iface = mac802154_add_iface; 375 local->phy->del_iface = mac802154_del_iface; 376 377 rc = wpan_phy_register(local->phy); 378 if (rc < 0) 379 goto out_wq; 380 381 rtnl_lock(); 382 383 mutex_lock(&local->iflist_mtx); 384 local->running = MAC802154_DEVICE_RUN; 385 mutex_unlock(&local->iflist_mtx); 386 387 rtnl_unlock(); 388 389 return 0; 390 391 out_wq: 392 destroy_workqueue(local->workqueue); 393 out: 394 return rc; 395 } 396 EXPORT_SYMBOL(ieee802154_register_hw); 397 398 void ieee802154_unregister_hw(struct ieee802154_hw *hw) 399 { 400 struct ieee802154_local *local = hw_to_local(hw); 401 struct ieee802154_sub_if_data *sdata, *next; 402 403 tasklet_kill(&local->tasklet); 404 flush_workqueue(local->workqueue); 405 destroy_workqueue(local->workqueue); 406 407 rtnl_lock(); 408 409 mutex_lock(&local->iflist_mtx); 410 local->running = MAC802154_DEVICE_STOPPED; 411 mutex_unlock(&local->iflist_mtx); 412 413 list_for_each_entry_safe(sdata, next, &local->interfaces, list) { 414 mutex_lock(&sdata->local->iflist_mtx); 415 list_del(&sdata->list); 416 mutex_unlock(&sdata->local->iflist_mtx); 417 418 unregister_netdevice(sdata->dev); 419 } 420 421 rtnl_unlock(); 422 423 wpan_phy_unregister(local->phy); 424 } 425 EXPORT_SYMBOL(ieee802154_unregister_hw); 426 427 MODULE_DESCRIPTION("IEEE 802.15.4 implementation"); 428 MODULE_LICENSE("GPL v2"); 429