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 = netdev_priv(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 if (local->ops->ieee_addr) { 65 __le64 addr = ieee802154_devaddr_from_raw(dev->dev_addr); 66 67 res = local->ops->ieee_addr(&local->hw, addr); 68 WARN_ON(res); 69 if (res) 70 goto err; 71 mac802154_dev_set_ieee_addr(dev); 72 } 73 74 netif_start_queue(dev); 75 return 0; 76 err: 77 sdata->local->open_count--; 78 79 return res; 80 } 81 82 int mac802154_slave_close(struct net_device *dev) 83 { 84 struct ieee802154_sub_if_data *sdata = netdev_priv(dev); 85 struct ieee802154_local *local = sdata->local; 86 87 ASSERT_RTNL(); 88 89 netif_stop_queue(dev); 90 91 mutex_lock(&sdata->local->iflist_mtx); 92 sdata->running = false; 93 mutex_unlock(&sdata->local->iflist_mtx); 94 95 if (!--local->open_count) 96 local->ops->stop(&local->hw); 97 98 return 0; 99 } 100 101 static int 102 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev) 103 { 104 struct ieee802154_sub_if_data *sdata; 105 struct ieee802154_local *local; 106 int err; 107 108 local = wpan_phy_priv(phy); 109 110 sdata = netdev_priv(dev); 111 sdata->dev = dev; 112 sdata->local = local; 113 114 dev->needed_headroom = local->hw.extra_tx_headroom; 115 116 SET_NETDEV_DEV(dev, &local->phy->dev); 117 118 mutex_lock(&local->iflist_mtx); 119 if (!local->running) { 120 mutex_unlock(&local->iflist_mtx); 121 return -ENODEV; 122 } 123 mutex_unlock(&local->iflist_mtx); 124 125 err = register_netdev(dev); 126 if (err < 0) 127 return err; 128 129 rtnl_lock(); 130 mutex_lock(&local->iflist_mtx); 131 list_add_tail_rcu(&sdata->list, &local->interfaces); 132 mutex_unlock(&local->iflist_mtx); 133 rtnl_unlock(); 134 135 return 0; 136 } 137 138 static void 139 mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev) 140 { 141 struct ieee802154_sub_if_data *sdata; 142 143 ASSERT_RTNL(); 144 145 sdata = netdev_priv(dev); 146 147 BUG_ON(sdata->local->phy != phy); 148 149 mutex_lock(&sdata->local->iflist_mtx); 150 list_del_rcu(&sdata->list); 151 mutex_unlock(&sdata->local->iflist_mtx); 152 153 synchronize_rcu(); 154 unregister_netdevice(sdata->dev); 155 } 156 157 static struct net_device * 158 mac802154_add_iface(struct wpan_phy *phy, const char *name, int type) 159 { 160 struct net_device *dev; 161 int err = -ENOMEM; 162 163 switch (type) { 164 case IEEE802154_DEV_MONITOR: 165 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), 166 name, NET_NAME_UNKNOWN, 167 mac802154_monitor_setup); 168 break; 169 case IEEE802154_DEV_WPAN: 170 dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data), 171 name, NET_NAME_UNKNOWN, 172 mac802154_wpan_setup); 173 break; 174 default: 175 dev = NULL; 176 err = -EINVAL; 177 break; 178 } 179 if (!dev) 180 goto err; 181 182 err = mac802154_netdev_register(phy, dev); 183 if (err) 184 goto err_free; 185 186 dev_hold(dev); /* we return an incremented device refcount */ 187 return dev; 188 189 err_free: 190 free_netdev(dev); 191 err: 192 return ERR_PTR(err); 193 } 194 195 static int mac802154_set_txpower(struct wpan_phy *phy, int db) 196 { 197 struct ieee802154_local *local = wpan_phy_priv(phy); 198 199 return local->ops->set_txpower(&local->hw, db); 200 } 201 202 static int mac802154_set_lbt(struct wpan_phy *phy, bool on) 203 { 204 struct ieee802154_local *local = wpan_phy_priv(phy); 205 206 return local->ops->set_lbt(&local->hw, on); 207 } 208 209 static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode) 210 { 211 struct ieee802154_local *local = wpan_phy_priv(phy); 212 213 return local->ops->set_cca_mode(&local->hw, mode); 214 } 215 216 static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level) 217 { 218 struct ieee802154_local *local = wpan_phy_priv(phy); 219 220 return local->ops->set_cca_ed_level(&local->hw, level); 221 } 222 223 static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be, 224 u8 max_be, u8 retries) 225 { 226 struct ieee802154_local *local = wpan_phy_priv(phy); 227 228 return local->ops->set_csma_params(&local->hw, min_be, max_be, retries); 229 } 230 231 static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries) 232 { 233 struct ieee802154_local *local = wpan_phy_priv(phy); 234 235 return local->ops->set_frame_retries(&local->hw, retries); 236 } 237 238 struct ieee802154_hw * 239 ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops) 240 { 241 struct wpan_phy *phy; 242 struct ieee802154_local *local; 243 size_t priv_size; 244 245 if (!ops || !ops->xmit || !ops->ed || !ops->start || 246 !ops->stop || !ops->set_channel) { 247 pr_err("undefined IEEE802.15.4 device operations\n"); 248 return NULL; 249 } 250 251 /* Ensure 32-byte alignment of our private data and hw private data. 252 * We use the wpan_phy priv data for both our ieee802154_local and for 253 * the driver's private data 254 * 255 * in memory it'll be like this: 256 * 257 * +-------------------------+ 258 * | struct wpan_phy | 259 * +-------------------------+ 260 * | struct ieee802154_local | 261 * +-------------------------+ 262 * | driver's private data | 263 * +-------------------------+ 264 * 265 * Due to ieee802154 layer isn't aware of driver and MAC structures, 266 * so lets align them here. 267 */ 268 269 priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; 270 271 phy = wpan_phy_alloc(priv_size); 272 if (!phy) { 273 pr_err("failure to allocate master IEEE802.15.4 device\n"); 274 return NULL; 275 } 276 277 local = wpan_phy_priv(phy); 278 local->phy = phy; 279 local->hw.phy = local->phy; 280 local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); 281 local->ops = ops; 282 283 INIT_LIST_HEAD(&local->interfaces); 284 mutex_init(&local->iflist_mtx); 285 286 return &local->hw; 287 } 288 EXPORT_SYMBOL(ieee802154_alloc_hw); 289 290 void ieee802154_free_hw(struct ieee802154_hw *hw) 291 { 292 struct ieee802154_local *local = mac802154_to_priv(hw); 293 294 BUG_ON(!list_empty(&local->interfaces)); 295 296 mutex_destroy(&local->iflist_mtx); 297 298 wpan_phy_free(local->phy); 299 } 300 EXPORT_SYMBOL(ieee802154_free_hw); 301 302 int ieee802154_register_hw(struct ieee802154_hw *hw) 303 { 304 struct ieee802154_local *local = mac802154_to_priv(hw); 305 int rc = -ENOSYS; 306 307 if (hw->flags & IEEE802154_HW_TXPOWER) { 308 if (!local->ops->set_txpower) 309 goto out; 310 311 local->phy->set_txpower = mac802154_set_txpower; 312 } 313 314 if (hw->flags & IEEE802154_HW_LBT) { 315 if (!local->ops->set_lbt) 316 goto out; 317 318 local->phy->set_lbt = mac802154_set_lbt; 319 } 320 321 if (hw->flags & IEEE802154_HW_CCA_MODE) { 322 if (!local->ops->set_cca_mode) 323 goto out; 324 325 local->phy->set_cca_mode = mac802154_set_cca_mode; 326 } 327 328 if (hw->flags & IEEE802154_HW_CCA_ED_LEVEL) { 329 if (!local->ops->set_cca_ed_level) 330 goto out; 331 332 local->phy->set_cca_ed_level = mac802154_set_cca_ed_level; 333 } 334 335 if (hw->flags & IEEE802154_HW_CSMA_PARAMS) { 336 if (!local->ops->set_csma_params) 337 goto out; 338 339 local->phy->set_csma_params = mac802154_set_csma_params; 340 } 341 342 if (hw->flags & IEEE802154_HW_FRAME_RETRIES) { 343 if (!local->ops->set_frame_retries) 344 goto out; 345 346 local->phy->set_frame_retries = mac802154_set_frame_retries; 347 } 348 349 local->dev_workqueue = 350 create_singlethread_workqueue(wpan_phy_name(local->phy)); 351 if (!local->dev_workqueue) { 352 rc = -ENOMEM; 353 goto out; 354 } 355 356 wpan_phy_set_dev(local->phy, local->hw.parent); 357 358 local->phy->add_iface = mac802154_add_iface; 359 local->phy->del_iface = mac802154_del_iface; 360 361 rc = wpan_phy_register(local->phy); 362 if (rc < 0) 363 goto out_wq; 364 365 rtnl_lock(); 366 367 mutex_lock(&local->iflist_mtx); 368 local->running = MAC802154_DEVICE_RUN; 369 mutex_unlock(&local->iflist_mtx); 370 371 rtnl_unlock(); 372 373 return 0; 374 375 out_wq: 376 destroy_workqueue(local->dev_workqueue); 377 out: 378 return rc; 379 } 380 EXPORT_SYMBOL(ieee802154_register_hw); 381 382 void ieee802154_unregister_hw(struct ieee802154_hw *hw) 383 { 384 struct ieee802154_local *local = mac802154_to_priv(hw); 385 struct ieee802154_sub_if_data *sdata, *next; 386 387 flush_workqueue(local->dev_workqueue); 388 destroy_workqueue(local->dev_workqueue); 389 390 rtnl_lock(); 391 392 mutex_lock(&local->iflist_mtx); 393 local->running = MAC802154_DEVICE_STOPPED; 394 mutex_unlock(&local->iflist_mtx); 395 396 list_for_each_entry_safe(sdata, next, &local->interfaces, list) { 397 mutex_lock(&sdata->local->iflist_mtx); 398 list_del(&sdata->list); 399 mutex_unlock(&sdata->local->iflist_mtx); 400 401 unregister_netdevice(sdata->dev); 402 } 403 404 rtnl_unlock(); 405 406 wpan_phy_unregister(local->phy); 407 } 408 EXPORT_SYMBOL(ieee802154_unregister_hw); 409 410 MODULE_DESCRIPTION("IEEE 802.15.4 implementation"); 411 MODULE_LICENSE("GPL v2"); 412