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 | */ |