mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: Alexander Aring <alex.aring@gmail.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
		
							parent
							
								
									190ac1ca33
								
							
						
					
					
						commit
						fcf39e6e88
					
				
					 3 changed files with 109 additions and 3 deletions
				
			
		| 
						 | 
				
			
			@ -66,6 +66,12 @@ struct wpan_dev {
 | 
			
		|||
	struct wpan_phy *wpan_phy;
 | 
			
		||||
	int iftype;
 | 
			
		||||
 | 
			
		||||
	/* the remainder of this struct should be private to cfg802154 */
 | 
			
		||||
	struct list_head list;
 | 
			
		||||
	struct net_device *netdev;
 | 
			
		||||
 | 
			
		||||
	u32 identifier;
 | 
			
		||||
 | 
			
		||||
	/* MAC PIB */
 | 
			
		||||
	__le16 pan_id;
 | 
			
		||||
	__le16 short_addr;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,12 +102,15 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
 | 
			
		|||
 | 
			
		||||
	mutex_init(&rdev->wpan_phy.pib_lock);
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&rdev->wpan_dev_list);
 | 
			
		||||
	device_initialize(&rdev->wpan_phy.dev);
 | 
			
		||||
	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.platform_data = rdev;
 | 
			
		||||
 | 
			
		||||
	init_waitqueue_head(&rdev->dev_wait);
 | 
			
		||||
 | 
			
		||||
	return &rdev->wpan_phy;
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(wpan_phy_new);
 | 
			
		||||
| 
						 | 
				
			
			@ -140,13 +143,18 @@ void wpan_phy_unregister(struct wpan_phy *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();
 | 
			
		||||
	/* TODO nl802154 phy notify */
 | 
			
		||||
	/* 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
 | 
			
		||||
	 * it impossible to find from userspace.
 | 
			
		||||
| 
						 | 
				
			
			@ -173,6 +181,79 @@ void cfg802154_dev_free(struct cfg802154_registered_device *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)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
| 
						 | 
				
			
			@ -181,11 +262,18 @@ static int __init wpan_phy_class_init(void)
 | 
			
		|||
	if (rc)
 | 
			
		||||
		goto err;
 | 
			
		||||
 | 
			
		||||
	rc = ieee802154_nl_init();
 | 
			
		||||
	rc = register_netdevice_notifier(&cfg802154_netdev_notifier);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto err_nl;
 | 
			
		||||
 | 
			
		||||
	rc = ieee802154_nl_init();
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto err_notifier;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_notifier:
 | 
			
		||||
	unregister_netdevice_notifier(&cfg802154_netdev_notifier);
 | 
			
		||||
err_nl:
 | 
			
		||||
	wpan_phy_sysfs_exit();
 | 
			
		||||
err:
 | 
			
		||||
| 
						 | 
				
			
			@ -196,6 +284,7 @@ subsys_initcall(wpan_phy_class_init);
 | 
			
		|||
static void __exit wpan_phy_class_exit(void)
 | 
			
		||||
{
 | 
			
		||||
	ieee802154_nl_exit();
 | 
			
		||||
	unregister_netdevice_notifier(&cfg802154_netdev_notifier);
 | 
			
		||||
	wpan_phy_sysfs_exit();
 | 
			
		||||
}
 | 
			
		||||
module_exit(wpan_phy_class_exit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,17 @@ struct cfg802154_registered_device {
 | 
			
		|||
	/* wpan_phy index, internal only */
 | 
			
		||||
	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(),
 | 
			
		||||
	 * and it should at least be aligned to NETDEV_ALIGN
 | 
			
		||||
	 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue