diff options
| author | Alexander Aring <alex.aring@gmail.com> | 2014-11-09 02:36:50 -0500 |
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2014-11-09 13:50:28 -0500 |
| commit | fcf39e6e88e9492f6688ec8ba4e1be622b904232 (patch) | |
| tree | ae87d1f093f7b8baa69cc438af36d14ba1866abe /net/ieee802154 | |
| parent | 190ac1ca33442dc25a172ece0f34746a7e1514f3 (diff) | |
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>
Diffstat (limited to 'net/ieee802154')
| -rw-r--r-- | net/ieee802154/core.c | 95 | ||||
| -rw-r--r-- | net/ieee802154/core.h | 11 |
2 files changed, 103 insertions, 3 deletions
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 11a1d2ed5b26..3ee00bf0e514 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c | |||
| @@ -102,12 +102,15 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size) | |||
| 102 | 102 | ||
| 103 | mutex_init(&rdev->wpan_phy.pib_lock); | 103 | mutex_init(&rdev->wpan_phy.pib_lock); |
| 104 | 104 | ||
| 105 | INIT_LIST_HEAD(&rdev->wpan_dev_list); | ||
| 105 | device_initialize(&rdev->wpan_phy.dev); | 106 | device_initialize(&rdev->wpan_phy.dev); |
| 106 | dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx); | 107 | dev_set_name(&rdev->wpan_phy.dev, "wpan-phy%d", rdev->wpan_phy_idx); |
| 107 | 108 | ||
| 108 | rdev->wpan_phy.dev.class = &wpan_phy_class; | 109 | rdev->wpan_phy.dev.class = &wpan_phy_class; |
| 109 | rdev->wpan_phy.dev.platform_data = rdev; | 110 | rdev->wpan_phy.dev.platform_data = rdev; |
| 110 | 111 | ||
| 112 | init_waitqueue_head(&rdev->dev_wait); | ||
| 113 | |||
| 111 | return &rdev->wpan_phy; | 114 | return &rdev->wpan_phy; |
| 112 | } | 115 | } |
| 113 | EXPORT_SYMBOL(wpan_phy_new); | 116 | EXPORT_SYMBOL(wpan_phy_new); |
| @@ -140,13 +143,18 @@ void wpan_phy_unregister(struct wpan_phy *phy) | |||
| 140 | { | 143 | { |
| 141 | struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); | 144 | struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(phy); |
| 142 | 145 | ||
| 143 | /* TODO open count */ | 146 | wait_event(rdev->dev_wait, ({ |
| 147 | int __count; | ||
| 148 | rtnl_lock(); | ||
| 149 | __count = rdev->opencount; | ||
| 150 | rtnl_unlock(); | ||
| 151 | __count == 0; })); | ||
| 144 | 152 | ||
| 145 | rtnl_lock(); | 153 | rtnl_lock(); |
| 146 | /* TODO nl802154 phy notify */ | 154 | /* TODO nl802154 phy notify */ |
| 147 | /* TODO phy registered lock */ | 155 | /* TODO phy registered lock */ |
| 148 | 156 | ||
| 149 | /* TODO WARN_ON wpan_dev_list */ | 157 | WARN_ON(!list_empty(&rdev->wpan_dev_list)); |
| 150 | 158 | ||
| 151 | /* First remove the hardware from everywhere, this makes | 159 | /* First remove the hardware from everywhere, this makes |
| 152 | * it impossible to find from userspace. | 160 | * it impossible to find from userspace. |
| @@ -173,6 +181,79 @@ void cfg802154_dev_free(struct cfg802154_registered_device *rdev) | |||
| 173 | kfree(rdev); | 181 | kfree(rdev); |
| 174 | } | 182 | } |
| 175 | 183 | ||
| 184 | static void | ||
| 185 | cfg802154_update_iface_num(struct cfg802154_registered_device *rdev, | ||
| 186 | int iftype, int num) | ||
| 187 | { | ||
| 188 | ASSERT_RTNL(); | ||
| 189 | |||
| 190 | rdev->num_running_ifaces += num; | ||
| 191 | } | ||
| 192 | |||
| 193 | static int cfg802154_netdev_notifier_call(struct notifier_block *nb, | ||
| 194 | unsigned long state, void *ptr) | ||
| 195 | { | ||
| 196 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | ||
| 197 | struct wpan_dev *wpan_dev = dev->ieee802154_ptr; | ||
| 198 | struct cfg802154_registered_device *rdev; | ||
| 199 | |||
| 200 | if (!wpan_dev) | ||
| 201 | return NOTIFY_DONE; | ||
| 202 | |||
| 203 | rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy); | ||
| 204 | |||
| 205 | /* TODO WARN_ON unspec type */ | ||
| 206 | |||
| 207 | switch (state) { | ||
| 208 | /* TODO NETDEV_DEVTYPE */ | ||
| 209 | case NETDEV_REGISTER: | ||
| 210 | wpan_dev->identifier = ++rdev->wpan_dev_id; | ||
| 211 | list_add_rcu(&wpan_dev->list, &rdev->wpan_dev_list); | ||
| 212 | rdev->devlist_generation++; | ||
| 213 | |||
| 214 | wpan_dev->netdev = dev; | ||
| 215 | break; | ||
| 216 | case NETDEV_DOWN: | ||
| 217 | cfg802154_update_iface_num(rdev, wpan_dev->iftype, -1); | ||
| 218 | |||
| 219 | rdev->opencount--; | ||
| 220 | wake_up(&rdev->dev_wait); | ||
| 221 | break; | ||
| 222 | case NETDEV_UP: | ||
| 223 | cfg802154_update_iface_num(rdev, wpan_dev->iftype, 1); | ||
| 224 | |||
| 225 | rdev->opencount++; | ||
| 226 | break; | ||
| 227 | case NETDEV_UNREGISTER: | ||
| 228 | /* It is possible to get NETDEV_UNREGISTER | ||
| 229 | * multiple times. To detect that, check | ||
| 230 | * that the interface is still on the list | ||
| 231 | * of registered interfaces, and only then | ||
| 232 | * remove and clean it up. | ||
| 233 | */ | ||
| 234 | if (!list_empty(&wpan_dev->list)) { | ||
| 235 | list_del_rcu(&wpan_dev->list); | ||
| 236 | rdev->devlist_generation++; | ||
| 237 | } | ||
| 238 | /* synchronize (so that we won't find this netdev | ||
| 239 | * from other code any more) and then clear the list | ||
| 240 | * head so that the above code can safely check for | ||
| 241 | * !list_empty() to avoid double-cleanup. | ||
| 242 | */ | ||
| 243 | synchronize_rcu(); | ||
| 244 | INIT_LIST_HEAD(&wpan_dev->list); | ||
| 245 | break; | ||
| 246 | default: | ||
| 247 | return NOTIFY_DONE; | ||
| 248 | } | ||
| 249 | |||
| 250 | return NOTIFY_OK; | ||
| 251 | } | ||
| 252 | |||
| 253 | static struct notifier_block cfg802154_netdev_notifier = { | ||
| 254 | .notifier_call = cfg802154_netdev_notifier_call, | ||
| 255 | }; | ||
| 256 | |||
| 176 | static int __init wpan_phy_class_init(void) | 257 | static int __init wpan_phy_class_init(void) |
| 177 | { | 258 | { |
| 178 | int rc; | 259 | int rc; |
| @@ -181,11 +262,18 @@ static int __init wpan_phy_class_init(void) | |||
| 181 | if (rc) | 262 | if (rc) |
| 182 | goto err; | 263 | goto err; |
| 183 | 264 | ||
| 184 | rc = ieee802154_nl_init(); | 265 | rc = register_netdevice_notifier(&cfg802154_netdev_notifier); |
| 185 | if (rc) | 266 | if (rc) |
| 186 | goto err_nl; | 267 | goto err_nl; |
| 187 | 268 | ||
| 269 | rc = ieee802154_nl_init(); | ||
| 270 | if (rc) | ||
| 271 | goto err_notifier; | ||
| 272 | |||
| 188 | return 0; | 273 | return 0; |
| 274 | |||
| 275 | err_notifier: | ||
| 276 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); | ||
| 189 | err_nl: | 277 | err_nl: |
| 190 | wpan_phy_sysfs_exit(); | 278 | wpan_phy_sysfs_exit(); |
| 191 | err: | 279 | err: |
| @@ -196,6 +284,7 @@ subsys_initcall(wpan_phy_class_init); | |||
| 196 | static void __exit wpan_phy_class_exit(void) | 284 | static void __exit wpan_phy_class_exit(void) |
| 197 | { | 285 | { |
| 198 | ieee802154_nl_exit(); | 286 | ieee802154_nl_exit(); |
| 287 | unregister_netdevice_notifier(&cfg802154_netdev_notifier); | ||
| 199 | wpan_phy_sysfs_exit(); | 288 | wpan_phy_sysfs_exit(); |
| 200 | } | 289 | } |
| 201 | module_exit(wpan_phy_class_exit); | 290 | module_exit(wpan_phy_class_exit); |
diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h index 38887cb2eaf4..e708d9d5878b 100644 --- a/net/ieee802154/core.h +++ b/net/ieee802154/core.h | |||
| @@ -10,6 +10,17 @@ struct cfg802154_registered_device { | |||
| 10 | /* wpan_phy index, internal only */ | 10 | /* wpan_phy index, internal only */ |
| 11 | int wpan_phy_idx; | 11 | int wpan_phy_idx; |
| 12 | 12 | ||
| 13 | /* also protected by devlist_mtx */ | ||
| 14 | int opencount; | ||
| 15 | wait_queue_head_t dev_wait; | ||
| 16 | |||
| 17 | /* protected by RTNL only */ | ||
| 18 | int num_running_ifaces; | ||
| 19 | |||
| 20 | /* associated wpan interfaces, protected by rtnl or RCU */ | ||
| 21 | struct list_head wpan_dev_list; | ||
| 22 | int devlist_generation, wpan_dev_id; | ||
| 23 | |||
| 13 | /* must be last because of the way we do wpan_phy_priv(), | 24 | /* must be last because of the way we do wpan_phy_priv(), |
| 14 | * and it should at least be aligned to NETDEV_ALIGN | 25 | * and it should at least be aligned to NETDEV_ALIGN |
| 15 | */ | 26 | */ |
