Commit fcf39e6e authored by Alexander Aring's avatar Alexander Aring Committed by Marcel Holtmann

ieee802154: add wpan_dev_list

This patch adds a wpan_dev_list list into cfg802154_registered_device
struct. Also adding new wpan_dev into this list while
cfg802154_netdev_notifier_call. This behaviour is mostly grab from
wireless core.c implementation and is needed for preparing nl802154
framework.
Signed-off-by: default avatarAlexander Aring <alex.aring@gmail.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 190ac1ca
...@@ -66,6 +66,12 @@ struct wpan_dev { ...@@ -66,6 +66,12 @@ struct wpan_dev {
struct wpan_phy *wpan_phy; struct wpan_phy *wpan_phy;
int iftype; int iftype;
/* the remainder of this struct should be private to cfg802154 */
struct list_head list;
struct net_device *netdev;
u32 identifier;
/* MAC PIB */ /* MAC PIB */
__le16 pan_id; __le16 pan_id;
__le16 short_addr; __le16 short_addr;
......
...@@ -102,12 +102,15 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) ...@@ -102,12 +102,15 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
mutex_init(&rdev->wpan_phy.pib_lock); mutex_init(&rdev->wpan_phy.pib_lock);
INIT_LIST_HEAD(&rdev->wpan_dev_list);
device_initialize(&rdev->wpan_phy.dev); device_initialize(&rdev->wpan_phy.dev);
dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx); dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx);
rdev->wpan_phy.dev.class = &wpan_phy_class; rdev->wpan_phy.dev.class = &wpan_phy_class;
rdev->wpan_phy.dev.platform_data = rdev; rdev->wpan_phy.dev.platform_data = rdev;
init_waitqueue_head(&rdev->dev_wait);
return &rdev->wpan_phy; return &rdev->wpan_phy;
} }
EXPORT_SYMBOL(wpan_phy_new); EXPORT_SYMBOL(wpan_phy_new);
...@@ -140,13 +143,18 @@ void wpan_phy_unregister(struct wpan_phy *phy) ...@@ -140,13 +143,18 @@ void wpan_phy_unregister(struct wpan_phy *phy)
{ {
struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy);
/* TODO open count */ wait_event(rdev->dev_wait, ({
int __count;
rtnl_lock();
__count = rdev->opencount;
rtnl_unlock();
__count == 0; }));
rtnl_lock(); rtnl_lock();
/* TODO nl802154 phy notify */ /* TODO nl802154 phy notify */
/* TODO phy registered lock */ /* TODO phy registered lock */
/* TODO WARN_ON wpan_dev_list */ WARN_ON(!list_empty(&rdev->wpan_dev_list));
/* First remove the hardware from everywhere, this makes /* First remove the hardware from everywhere, this makes
* it impossible to find from userspace. * it impossible to find from userspace.
...@@ -173,6 +181,79 @@ void cfg802154_dev_free(struct cfg802154_registered_device *rdev) ...@@ -173,6 +181,79 @@ void cfg802154_dev_free(struct cfg802154_registered_device *rdev)
kfree(rdev); kfree(rdev);
} }
static void
cfg802154_update_iface_num(struct cfg802154_registered_device *rdev,
int iftype, int num)
{
ASSERT_RTNL();
rdev->num_running_ifaces += num;
}
static int cfg802154_netdev_notifier_call(struct notifier_block *nb,
unsigned long state, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
struct cfg802154_registered_device *rdev;
if (!wpan_dev)
return NOTIFY_DONE;
rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
/* TODO WARN_ON unspec type */
switch (state) {
/* TODO NETDEV_DEVTYPE */
case NETDEV_REGISTER:
wpan_dev->identifier = ++rdev->wpan_dev_id;
list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list);
rdev->devlist_generation++;
wpan_dev->netdev = dev;
break;
case NETDEV_DOWN:
cfg802154_update_iface_num(rdev, wpan_dev->iftype, -1);
rdev->opencount--;
wake_up(&rdev->dev_wait);
break;
case NETDEV_UP:
cfg802154_update_iface_num(rdev, wpan_dev->iftype, 1);
rdev->opencount++;
break;
case NETDEV_UNREGISTER:
/* It is possible to get NETDEV_UNREGISTER
* multiple times. To detect that, check
* that the interface is still on the list
* of registered interfaces, and only then
* remove and clean it up.
*/
if (!list_empty(&wpan_dev->list)) {
list_del_rcu(&wpan_dev->list);
rdev->devlist_generation++;
}
/* synchronize (so that we won't find this netdev
* from other code any more) and then clear the list
* head so that the above code can safely check for
* !list_empty() to avoid double-cleanup.
*/
synchronize_rcu();
INIT_LIST_HEAD(&wpan_dev->list);
break;
default:
return NOTIFY_DONE;
}
return NOTIFY_OK;
}
static struct notifier_block cfg802154_netdev_notifier = {
.notifier_call = cfg802154_netdev_notifier_call,
};
static int __init wpan_phy_class_init(void) static int __init wpan_phy_class_init(void)
{ {
int rc; int rc;
...@@ -181,11 +262,18 @@ static int __init wpan_phy_class_init(void) ...@@ -181,11 +262,18 @@ static int __init wpan_phy_class_init(void)
if (rc) if (rc)
goto err; goto err;
rc = ieee802154_nl_init(); rc = register_netdevice_notifier(&cfg802154_netdev_notifier);
if (rc) if (rc)
goto err_nl; goto err_nl;
rc = ieee802154_nl_init();
if (rc)
goto err_notifier;
return 0; return 0;
err_notifier:
unregister_netdevice_notifier(&cfg802154_netdev_notifier);
err_nl: err_nl:
wpan_phy_sysfs_exit(); wpan_phy_sysfs_exit();
err: err:
...@@ -196,6 +284,7 @@ subsys_initcall(wpan_phy_class_init); ...@@ -196,6 +284,7 @@ subsys_initcall(wpan_phy_class_init);
static void __exit wpan_phy_class_exit(void) static void __exit wpan_phy_class_exit(void)
{ {
ieee802154_nl_exit(); ieee802154_nl_exit();
unregister_netdevice_notifier(&cfg802154_netdev_notifier);
wpan_phy_sysfs_exit(); wpan_phy_sysfs_exit();
} }
module_exit(wpan_phy_class_exit); module_exit(wpan_phy_class_exit);
......
...@@ -10,6 +10,17 @@ struct cfg802154_registered_device { ...@@ -10,6 +10,17 @@ struct cfg802154_registered_device {
/* wpan_phy index, internal only */ /* wpan_phy index, internal only */
int wpan_phy_idx; int wpan_phy_idx;
/* also protected by devlist_mtx */
int opencount;
wait_queue_head_t dev_wait;
/* protected by RTNL only */
int num_running_ifaces;
/* associated wpan interfaces, protected by rtnl or RCU */
struct list_head wpan_dev_list;
int devlist_generation, wpan_dev_id;
/* must be last because of the way we do wpan_phy_priv(), /* must be last because of the way we do wpan_phy_priv(),
* and it should at least be aligned to NETDEV_ALIGN * and it should at least be aligned to NETDEV_ALIGN
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment