xref: /openbmc/linux/net/mac802154/main.c (revision c5c47e67bcd24638a059b1b5e9ec18c95f8634ca)
1 /*
2  * Copyright (C) 2007-2012 Siemens AG
3  *
4  * Written by:
5  * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
6  *
7  * Based on the code from 'linux-zigbee.sourceforge.net' project.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2
11  * as published by the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18 
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/netdevice.h>
22 
23 #include <net/netlink.h>
24 #include <linux/nl802154.h>
25 #include <net/mac802154.h>
26 #include <net/ieee802154_netdev.h>
27 #include <net/route.h>
28 #include <net/cfg802154.h>
29 
30 #include "ieee802154_i.h"
31 
32 int mac802154_slave_open(struct net_device *dev)
33 {
34 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
35 	struct ieee802154_sub_if_data *subif;
36 	struct ieee802154_local *local = sdata->local;
37 	int res = 0;
38 
39 	ASSERT_RTNL();
40 
41 	if (sdata->type == IEEE802154_DEV_WPAN) {
42 		mutex_lock(&sdata->local->iflist_mtx);
43 		list_for_each_entry(subif, &sdata->local->interfaces, list) {
44 			if (subif != sdata && subif->type == sdata->type &&
45 			    subif->running) {
46 				mutex_unlock(&sdata->local->iflist_mtx);
47 				return -EBUSY;
48 			}
49 		}
50 		mutex_unlock(&sdata->local->iflist_mtx);
51 	}
52 
53 	mutex_lock(&sdata->local->iflist_mtx);
54 	sdata->running = true;
55 	mutex_unlock(&sdata->local->iflist_mtx);
56 
57 	if (local->open_count++ == 0) {
58 		res = local->ops->start(&local->hw);
59 		WARN_ON(res);
60 		if (res)
61 			goto err;
62 	}
63 
64 	netif_start_queue(dev);
65 	return 0;
66 err:
67 	sdata->local->open_count--;
68 
69 	return res;
70 }
71 
72 int mac802154_slave_close(struct net_device *dev)
73 {
74 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
75 	struct ieee802154_local *local = sdata->local;
76 
77 	ASSERT_RTNL();
78 
79 	netif_stop_queue(dev);
80 
81 	mutex_lock(&sdata->local->iflist_mtx);
82 	sdata->running = false;
83 	mutex_unlock(&sdata->local->iflist_mtx);
84 
85 	if (!--local->open_count)
86 		local->ops->stop(&local->hw);
87 
88 	return 0;
89 }
90 
91 static int
92 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
93 {
94 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
95 	struct ieee802154_local *local;
96 	int err;
97 
98 	local = wpan_phy_priv(phy);
99 
100 	sdata->dev = dev;
101 	sdata->local = local;
102 
103 	dev->needed_headroom = local->hw.extra_tx_headroom;
104 
105 	SET_NETDEV_DEV(dev, &local->phy->dev);
106 
107 	mutex_lock(&local->iflist_mtx);
108 	if (!local->running) {
109 		mutex_unlock(&local->iflist_mtx);
110 		return -ENODEV;
111 	}
112 	mutex_unlock(&local->iflist_mtx);
113 
114 	err = register_netdev(dev);
115 	if (err < 0)
116 		return err;
117 
118 	rtnl_lock();
119 	mutex_lock(&local->iflist_mtx);
120 	list_add_tail_rcu(&sdata->list, &local->interfaces);
121 	mutex_unlock(&local->iflist_mtx);
122 	rtnl_unlock();
123 
124 	return 0;
125 }
126 
127 static void
128 mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
129 {
130 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
131 
132 	ASSERT_RTNL();
133 
134 	BUG_ON(sdata->local->phy != phy);
135 
136 	mutex_lock(&sdata->local->iflist_mtx);
137 	list_del_rcu(&sdata->list);
138 	mutex_unlock(&sdata->local->iflist_mtx);
139 
140 	synchronize_rcu();
141 	unregister_netdevice(sdata->dev);
142 }
143 
144 static struct net_device *
145 mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
146 {
147 	struct net_device *dev;
148 	int err = -ENOMEM;
149 
150 	switch (type) {
151 	case IEEE802154_DEV_MONITOR:
152 		dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
153 				   name, NET_NAME_UNKNOWN,
154 				   mac802154_monitor_setup);
155 		break;
156 	case IEEE802154_DEV_WPAN:
157 		dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
158 				   name, NET_NAME_UNKNOWN,
159 				   mac802154_wpan_setup);
160 		break;
161 	default:
162 		dev = NULL;
163 		err = -EINVAL;
164 		break;
165 	}
166 	if (!dev)
167 		goto err;
168 
169 	err = mac802154_netdev_register(phy, dev);
170 	if (err)
171 		goto err_free;
172 
173 	dev_hold(dev); /* we return an incremented device refcount */
174 	return dev;
175 
176 err_free:
177 	free_netdev(dev);
178 err:
179 	return ERR_PTR(err);
180 }
181 
182 static int mac802154_set_txpower(struct wpan_phy *phy, int db)
183 {
184 	struct ieee802154_local *local = wpan_phy_priv(phy);
185 
186 	return local->ops->set_txpower(&local->hw, db);
187 }
188 
189 static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
190 {
191 	struct ieee802154_local *local = wpan_phy_priv(phy);
192 
193 	return local->ops->set_lbt(&local->hw, on);
194 }
195 
196 static int mac802154_set_cca_mode(struct wpan_phy *phy, u8 mode)
197 {
198 	struct ieee802154_local *local = wpan_phy_priv(phy);
199 
200 	return local->ops->set_cca_mode(&local->hw, mode);
201 }
202 
203 static int mac802154_set_cca_ed_level(struct wpan_phy *phy, s32 level)
204 {
205 	struct ieee802154_local *local = wpan_phy_priv(phy);
206 
207 	return local->ops->set_cca_ed_level(&local->hw, level);
208 }
209 
210 static int mac802154_set_csma_params(struct wpan_phy *phy, u8 min_be,
211 				     u8 max_be, u8 retries)
212 {
213 	struct ieee802154_local *local = wpan_phy_priv(phy);
214 
215 	return local->ops->set_csma_params(&local->hw, min_be, max_be, retries);
216 }
217 
218 static int mac802154_set_frame_retries(struct wpan_phy *phy, s8 retries)
219 {
220 	struct ieee802154_local *local = wpan_phy_priv(phy);
221 
222 	return local->ops->set_frame_retries(&local->hw, retries);
223 }
224 
225 static void ieee802154_tasklet_handler(unsigned long data)
226 {
227 	struct ieee802154_local *local = (struct ieee802154_local *)data;
228 	struct sk_buff *skb;
229 
230 	while ((skb = skb_dequeue(&local->skb_queue))) {
231 		switch (skb->pkt_type) {
232 		case IEEE802154_RX_MSG:
233 			/* Clear skb->pkt_type in order to not confuse kernel
234 			 * netstack.
235 			 */
236 			skb->pkt_type = 0;
237 			ieee802154_rx(&local->hw, skb);
238 			break;
239 		default:
240 			WARN(1, "mac802154: Packet is of unknown type %d\n",
241 			     skb->pkt_type);
242 			kfree_skb(skb);
243 			break;
244 		}
245 	}
246 }
247 
248 struct ieee802154_hw *
249 ieee802154_alloc_hw(size_t priv_data_len, struct ieee802154_ops *ops)
250 {
251 	struct wpan_phy *phy;
252 	struct ieee802154_local *local;
253 	size_t priv_size;
254 
255 	if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
256 	    !ops->start || !ops->stop || !ops->set_channel) {
257 		pr_err("undefined IEEE802.15.4 device operations\n");
258 		return NULL;
259 	}
260 
261 	/* Ensure 32-byte alignment of our private data and hw private data.
262 	 * We use the wpan_phy priv data for both our ieee802154_local and for
263 	 * the driver's private data
264 	 *
265 	 * in memory it'll be like this:
266 	 *
267 	 * +-------------------------+
268 	 * | struct wpan_phy         |
269 	 * +-------------------------+
270 	 * | struct ieee802154_local |
271 	 * +-------------------------+
272 	 * | driver's private data   |
273 	 * +-------------------------+
274 	 *
275 	 * Due to ieee802154 layer isn't aware of driver and MAC structures,
276 	 * so lets align them here.
277 	 */
278 
279 	priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
280 
281 	phy = wpan_phy_alloc(priv_size);
282 	if (!phy) {
283 		pr_err("failure to allocate master IEEE802.15.4 device\n");
284 		return NULL;
285 	}
286 
287 	local = wpan_phy_priv(phy);
288 	local->phy = phy;
289 	local->hw.phy = local->phy;
290 	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
291 	local->ops = ops;
292 
293 	INIT_LIST_HEAD(&local->interfaces);
294 	mutex_init(&local->iflist_mtx);
295 
296 	tasklet_init(&local->tasklet,
297 		     ieee802154_tasklet_handler,
298 		     (unsigned long)local);
299 
300 	skb_queue_head_init(&local->skb_queue);
301 
302 	return &local->hw;
303 }
304 EXPORT_SYMBOL(ieee802154_alloc_hw);
305 
306 void ieee802154_free_hw(struct ieee802154_hw *hw)
307 {
308 	struct ieee802154_local *local = hw_to_local(hw);
309 
310 	BUG_ON(!list_empty(&local->interfaces));
311 
312 	mutex_destroy(&local->iflist_mtx);
313 
314 	wpan_phy_free(local->phy);
315 }
316 EXPORT_SYMBOL(ieee802154_free_hw);
317 
318 int ieee802154_register_hw(struct ieee802154_hw *hw)
319 {
320 	struct ieee802154_local *local = hw_to_local(hw);
321 	int rc = -ENOSYS;
322 
323 	if (hw->flags & IEEE802154_HW_TXPOWER) {
324 		if (!local->ops->set_txpower)
325 			goto out;
326 
327 		local->phy->set_txpower = mac802154_set_txpower;
328 	}
329 
330 	if (hw->flags & IEEE802154_HW_LBT) {
331 		if (!local->ops->set_lbt)
332 			goto out;
333 
334 		local->phy->set_lbt = mac802154_set_lbt;
335 	}
336 
337 	if (hw->flags & IEEE802154_HW_CCA_MODE) {
338 		if (!local->ops->set_cca_mode)
339 			goto out;
340 
341 		local->phy->set_cca_mode = mac802154_set_cca_mode;
342 	}
343 
344 	if (hw->flags & IEEE802154_HW_CCA_ED_LEVEL) {
345 		if (!local->ops->set_cca_ed_level)
346 			goto out;
347 
348 		local->phy->set_cca_ed_level = mac802154_set_cca_ed_level;
349 	}
350 
351 	if (hw->flags & IEEE802154_HW_CSMA_PARAMS) {
352 		if (!local->ops->set_csma_params)
353 			goto out;
354 
355 		local->phy->set_csma_params = mac802154_set_csma_params;
356 	}
357 
358 	if (hw->flags & IEEE802154_HW_FRAME_RETRIES) {
359 		if (!local->ops->set_frame_retries)
360 			goto out;
361 
362 		local->phy->set_frame_retries = mac802154_set_frame_retries;
363 	}
364 
365 	local->workqueue =
366 		create_singlethread_workqueue(wpan_phy_name(local->phy));
367 	if (!local->workqueue) {
368 		rc = -ENOMEM;
369 		goto out;
370 	}
371 
372 	wpan_phy_set_dev(local->phy, local->hw.parent);
373 
374 	local->phy->add_iface = mac802154_add_iface;
375 	local->phy->del_iface = mac802154_del_iface;
376 
377 	rc = wpan_phy_register(local->phy);
378 	if (rc < 0)
379 		goto out_wq;
380 
381 	rtnl_lock();
382 
383 	mutex_lock(&local->iflist_mtx);
384 	local->running = MAC802154_DEVICE_RUN;
385 	mutex_unlock(&local->iflist_mtx);
386 
387 	rtnl_unlock();
388 
389 	return 0;
390 
391 out_wq:
392 	destroy_workqueue(local->workqueue);
393 out:
394 	return rc;
395 }
396 EXPORT_SYMBOL(ieee802154_register_hw);
397 
398 void ieee802154_unregister_hw(struct ieee802154_hw *hw)
399 {
400 	struct ieee802154_local *local = hw_to_local(hw);
401 	struct ieee802154_sub_if_data *sdata, *next;
402 
403 	tasklet_kill(&local->tasklet);
404 	flush_workqueue(local->workqueue);
405 	destroy_workqueue(local->workqueue);
406 
407 	rtnl_lock();
408 
409 	mutex_lock(&local->iflist_mtx);
410 	local->running = MAC802154_DEVICE_STOPPED;
411 	mutex_unlock(&local->iflist_mtx);
412 
413 	list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
414 		mutex_lock(&sdata->local->iflist_mtx);
415 		list_del(&sdata->list);
416 		mutex_unlock(&sdata->local->iflist_mtx);
417 
418 		unregister_netdevice(sdata->dev);
419 	}
420 
421 	rtnl_unlock();
422 
423 	wpan_phy_unregister(local->phy);
424 }
425 EXPORT_SYMBOL(ieee802154_unregister_hw);
426 
427 MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
428 MODULE_LICENSE("GPL v2");
429