1 /* 2 * Copyright (C) 2007, 2008, 2009 Siemens AG 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 6 * as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 */ 14 15 #include <linux/slab.h> 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/device.h> 19 20 #include <net/cfg802154.h> 21 #include <net/rtnetlink.h> 22 23 #include "ieee802154.h" 24 #include "nl802154.h" 25 #include "sysfs.h" 26 #include "core.h" 27 28 /* name for sysfs, %d is appended */ 29 #define PHY_NAME "phy" 30 31 /* RCU-protected (and RTNL for writers) */ 32 LIST_HEAD(cfg802154_rdev_list); 33 int cfg802154_rdev_list_generation; 34 35 static int wpan_phy_match(struct device *dev, const void *data) 36 { 37 return !strcmp(dev_name(dev), (const char *)data); 38 } 39 40 struct wpan_phy *wpan_phy_find(const char *str) 41 { 42 struct device *dev; 43 44 if (WARN_ON(!str)) 45 return NULL; 46 47 dev = class_find_device(&wpan_phy_class, NULL, str, wpan_phy_match); 48 if (!dev) 49 return NULL; 50 51 return container_of(dev, struct wpan_phy, dev); 52 } 53 EXPORT_SYMBOL(wpan_phy_find); 54 55 struct wpan_phy_iter_data { 56 int (*fn)(struct wpan_phy *phy, void *data); 57 void *data; 58 }; 59 60 static int wpan_phy_iter(struct device *dev, void *_data) 61 { 62 struct wpan_phy_iter_data *wpid = _data; 63 struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); 64 65 return wpid->fn(phy, wpid->data); 66 } 67 68 int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), 69 void *data) 70 { 71 struct wpan_phy_iter_data wpid = { 72 .fn = fn, 73 .data = data, 74 }; 75 76 return class_for_each_device(&wpan_phy_class, NULL, 77 &wpid, wpan_phy_iter); 78 } 79 EXPORT_SYMBOL(wpan_phy_for_each); 80 81 struct cfg802154_registered_device * 82 cfg802154_rdev_by_wpan_phy_idx(int wpan_phy_idx) 83 { 84 struct cfg802154_registered_device *result = NULL, *rdev; 85 86 ASSERT_RTNL(); 87 88 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 89 if (rdev->wpan_phy_idx == wpan_phy_idx) { 90 result = rdev; 91 break; 92 } 93 } 94 95 return result; 96 } 97 98 struct wpan_phy *wpan_phy_idx_to_wpan_phy(int wpan_phy_idx) 99 { 100 struct cfg802154_registered_device *rdev; 101 102 ASSERT_RTNL(); 103 104 rdev = cfg802154_rdev_by_wpan_phy_idx(wpan_phy_idx); 105 if (!rdev) 106 return NULL; 107 return &rdev->wpan_phy; 108 } 109 110 struct wpan_phy * 111 wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) 112 { 113 static atomic_t wpan_phy_counter = ATOMIC_INIT(0); 114 struct cfg802154_registered_device *rdev; 115 size_t alloc_size; 116 117 alloc_size = sizeof(*rdev) + priv_size; 118 rdev = kzalloc(alloc_size, GFP_KERNEL); 119 if (!rdev) 120 return NULL; 121 122 rdev->ops = ops; 123 124 rdev->wpan_phy_idx = atomic_inc_return(&wpan_phy_counter); 125 126 if (unlikely(rdev->wpan_phy_idx < 0)) { 127 /* ugh, wrapped! */ 128 atomic_dec(&wpan_phy_counter); 129 kfree(rdev); 130 return NULL; 131 } 132 133 /* atomic_inc_return makes it start at 1, make it start at 0 */ 134 rdev->wpan_phy_idx--; 135 136 INIT_LIST_HEAD(&rdev->wpan_dev_list); 137 device_initialize(&rdev->wpan_phy.dev); 138 dev_set_name(&rdev->wpan_phy.dev, PHY_NAME "%d", rdev->wpan_phy_idx); 139 140 rdev->wpan_phy.dev.class = &wpan_phy_class; 141 rdev->wpan_phy.dev.platform_data = rdev; 142 143 wpan_phy_net_set(&rdev->wpan_phy, &init_net); 144 145 init_waitqueue_head(&rdev->dev_wait); 146 147 return &rdev->wpan_phy; 148 } 149 EXPORT_SYMBOL(wpan_phy_new); 150 151 int wpan_phy_register(struct wpan_phy *phy) 152 { 153 struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); 154 int ret; 155 156 rtnl_lock(); 157 ret = device_add(&phy->dev); 158 if (ret) { 159 rtnl_unlock(); 160 return ret; 161 } 162 163 list_add_rcu(&rdev->list, &cfg802154_rdev_list); 164 cfg802154_rdev_list_generation++; 165 166 /* TODO phy registered lock */ 167 rtnl_unlock(); 168 169 /* TODO nl802154 phy notify */ 170 171 return 0; 172 } 173 EXPORT_SYMBOL(wpan_phy_register); 174 175 void wpan_phy_unregister(struct wpan_phy *phy) 176 { 177 struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); 178 179 wait_event(rdev->dev_wait, ({ 180 int __count; 181 rtnl_lock(); 182 __count = rdev->opencount; 183 rtnl_unlock(); 184 __count == 0; })); 185 186 rtnl_lock(); 187 /* TODO nl802154 phy notify */ 188 /* TODO phy registered lock */ 189 190 WARN_ON(!list_empty(&rdev->wpan_dev_list)); 191 192 /* First remove the hardware from everywhere, this makes 193 * it impossible to find from userspace. 194 */ 195 list_del_rcu(&rdev->list); 196 synchronize_rcu(); 197 198 cfg802154_rdev_list_generation++; 199 200 device_del(&phy->dev); 201 202 rtnl_unlock(); 203 } 204 EXPORT_SYMBOL(wpan_phy_unregister); 205 206 void wpan_phy_free(struct wpan_phy *phy) 207 { 208 put_device(&phy->dev); 209 } 210 EXPORT_SYMBOL(wpan_phy_free); 211 212 int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, 213 struct net *net) 214 { 215 struct wpan_dev *wpan_dev; 216 int err = 0; 217 218 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) { 219 if (!wpan_dev->netdev) 220 continue; 221 wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 222 err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d"); 223 if (err) 224 break; 225 wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; 226 } 227 228 if (err) { 229 /* failed -- clean up to old netns */ 230 net = wpan_phy_net(&rdev->wpan_phy); 231 232 list_for_each_entry_continue_reverse(wpan_dev, 233 &rdev->wpan_dev_list, 234 list) { 235 if (!wpan_dev->netdev) 236 continue; 237 wpan_dev->netdev->features &= ~NETIF_F_NETNS_LOCAL; 238 err = dev_change_net_namespace(wpan_dev->netdev, net, 239 "wpan%d"); 240 WARN_ON(err); 241 wpan_dev->netdev->features |= NETIF_F_NETNS_LOCAL; 242 } 243 244 return err; 245 } 246 247 wpan_phy_net_set(&rdev->wpan_phy, net); 248 249 err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev)); 250 WARN_ON(err); 251 252 return 0; 253 } 254 255 void cfg802154_dev_free(struct cfg802154_registered_device *rdev) 256 { 257 kfree(rdev); 258 } 259 260 static void 261 cfg802154_update_iface_num(struct cfg802154_registered_device *rdev, 262 int iftype, int num) 263 { 264 ASSERT_RTNL(); 265 266 rdev->num_running_ifaces += num; 267 } 268 269 static int cfg802154_netdev_notifier_call(struct notifier_block *nb, 270 unsigned long state, void *ptr) 271 { 272 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 273 struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 274 struct cfg802154_registered_device *rdev; 275 276 if (!wpan_dev) 277 return NOTIFY_DONE; 278 279 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); 280 281 /* TODO WARN_ON unspec type */ 282 283 switch (state) { 284 /* TODO NETDEV_DEVTYPE */ 285 case NETDEV_REGISTER: 286 dev->features |= NETIF_F_NETNS_LOCAL; 287 wpan_dev->identifier = ++rdev->wpan_dev_id; 288 list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list); 289 rdev->devlist_generation++; 290 291 wpan_dev->netdev = dev; 292 break; 293 case NETDEV_DOWN: 294 cfg802154_update_iface_num(rdev, wpan_dev->iftype, -1); 295 296 rdev->opencount--; 297 wake_up(&rdev->dev_wait); 298 break; 299 case NETDEV_UP: 300 cfg802154_update_iface_num(rdev, wpan_dev->iftype, 1); 301 302 rdev->opencount++; 303 break; 304 case NETDEV_UNREGISTER: 305 /* It is possible to get NETDEV_UNREGISTER 306 * multiple times. To detect that, check 307 * that the interface is still on the list 308 * of registered interfaces, and only then 309 * remove and clean it up. 310 */ 311 if (!list_empty(&wpan_dev->list)) { 312 list_del_rcu(&wpan_dev->list); 313 rdev->devlist_generation++; 314 } 315 /* synchronize (so that we won't find this netdev 316 * from other code any more) and then clear the list 317 * head so that the above code can safely check for 318 * !list_empty() to avoid double-cleanup. 319 */ 320 synchronize_rcu(); 321 INIT_LIST_HEAD(&wpan_dev->list); 322 break; 323 default: 324 return NOTIFY_DONE; 325 } 326 327 return NOTIFY_OK; 328 } 329 330 static struct notifier_block cfg802154_netdev_notifier = { 331 .notifier_call = cfg802154_netdev_notifier_call, 332 }; 333 334 static void __net_exit cfg802154_pernet_exit(struct net *net) 335 { 336 struct cfg802154_registered_device *rdev; 337 338 rtnl_lock(); 339 list_for_each_entry(rdev, &cfg802154_rdev_list, list) { 340 if (net_eq(wpan_phy_net(&rdev->wpan_phy), net)) 341 WARN_ON(cfg802154_switch_netns(rdev, &init_net)); 342 } 343 rtnl_unlock(); 344 } 345 346 static struct pernet_operations cfg802154_pernet_ops = { 347 .exit = cfg802154_pernet_exit, 348 }; 349 350 static int __init wpan_phy_class_init(void) 351 { 352 int rc; 353 354 rc = register_pernet_device(&cfg802154_pernet_ops); 355 if (rc) 356 goto err; 357 358 rc = wpan_phy_sysfs_init(); 359 if (rc) 360 goto err_sysfs; 361 362 rc = register_netdevice_notifier(&cfg802154_netdev_notifier); 363 if (rc) 364 goto err_nl; 365 366 rc = ieee802154_nl_init(); 367 if (rc) 368 goto err_notifier; 369 370 rc = nl802154_init(); 371 if (rc) 372 goto err_ieee802154_nl; 373 374 return 0; 375 376 err_ieee802154_nl: 377 ieee802154_nl_exit(); 378 379 err_notifier: 380 unregister_netdevice_notifier(&cfg802154_netdev_notifier); 381 err_nl: 382 wpan_phy_sysfs_exit(); 383 err_sysfs: 384 unregister_pernet_device(&cfg802154_pernet_ops); 385 err: 386 return rc; 387 } 388 subsys_initcall(wpan_phy_class_init); 389 390 static void __exit wpan_phy_class_exit(void) 391 { 392 nl802154_exit(); 393 ieee802154_nl_exit(); 394 unregister_netdevice_notifier(&cfg802154_netdev_notifier); 395 wpan_phy_sysfs_exit(); 396 unregister_pernet_device(&cfg802154_pernet_ops); 397 } 398 module_exit(wpan_phy_class_exit); 399 400 MODULE_LICENSE("GPL v2"); 401 MODULE_DESCRIPTION("IEEE 802.15.4 configuration interface"); 402 MODULE_AUTHOR("Dmitry Eremin-Solenikov"); 403