xref: /openbmc/linux/net/mac802154/main.c (revision 5d65cae4bf6ffe29bba90f621e947922c5fb80db)
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 #include "driver-ops.h"
32 
33 static int
34 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
35 {
36 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
37 	struct ieee802154_local *local;
38 	int err;
39 
40 	local = wpan_phy_priv(phy);
41 
42 	sdata->dev = dev;
43 	sdata->local = local;
44 
45 	dev->needed_headroom = local->hw.extra_tx_headroom;
46 
47 	SET_NETDEV_DEV(dev, &local->phy->dev);
48 
49 	mutex_lock(&local->iflist_mtx);
50 	if (!local->started) {
51 		mutex_unlock(&local->iflist_mtx);
52 		return -ENODEV;
53 	}
54 	mutex_unlock(&local->iflist_mtx);
55 
56 	err = register_netdev(dev);
57 	if (err < 0)
58 		return err;
59 
60 	rtnl_lock();
61 	mutex_lock(&local->iflist_mtx);
62 	list_add_tail_rcu(&sdata->list, &local->interfaces);
63 	mutex_unlock(&local->iflist_mtx);
64 	rtnl_unlock();
65 
66 	return 0;
67 }
68 
69 static void
70 mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
71 {
72 	struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
73 
74 	ASSERT_RTNL();
75 
76 	BUG_ON(sdata->local->phy != phy);
77 
78 	mutex_lock(&sdata->local->iflist_mtx);
79 	list_del_rcu(&sdata->list);
80 	mutex_unlock(&sdata->local->iflist_mtx);
81 
82 	synchronize_rcu();
83 	unregister_netdevice(sdata->dev);
84 }
85 
86 static struct net_device *
87 mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
88 {
89 	struct net_device *dev;
90 	int err = -ENOMEM;
91 
92 	switch (type) {
93 	case IEEE802154_DEV_MONITOR:
94 		dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
95 				   name, NET_NAME_UNKNOWN,
96 				   mac802154_monitor_setup);
97 		break;
98 	case IEEE802154_DEV_WPAN:
99 		dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
100 				   name, NET_NAME_UNKNOWN,
101 				   mac802154_wpan_setup);
102 		break;
103 	default:
104 		dev = NULL;
105 		err = -EINVAL;
106 		break;
107 	}
108 	if (!dev)
109 		goto err;
110 
111 	err = mac802154_netdev_register(phy, dev);
112 	if (err)
113 		goto err_free;
114 
115 	dev_hold(dev); /* we return an incremented device refcount */
116 	return dev;
117 
118 err_free:
119 	free_netdev(dev);
120 err:
121 	return ERR_PTR(err);
122 }
123 
124 static void ieee802154_tasklet_handler(unsigned long data)
125 {
126 	struct ieee802154_local *local = (struct ieee802154_local *)data;
127 	struct sk_buff *skb;
128 
129 	while ((skb = skb_dequeue(&local->skb_queue))) {
130 		switch (skb->pkt_type) {
131 		case IEEE802154_RX_MSG:
132 			/* Clear skb->pkt_type in order to not confuse kernel
133 			 * netstack.
134 			 */
135 			skb->pkt_type = 0;
136 			ieee802154_rx(&local->hw, skb);
137 			break;
138 		default:
139 			WARN(1, "mac802154: Packet is of unknown type %d\n",
140 			     skb->pkt_type);
141 			kfree_skb(skb);
142 			break;
143 		}
144 	}
145 }
146 
147 struct ieee802154_hw *
148 ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
149 {
150 	struct wpan_phy *phy;
151 	struct ieee802154_local *local;
152 	size_t priv_size;
153 
154 	if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed ||
155 	    !ops->start || !ops->stop || !ops->set_channel) {
156 		pr_err("undefined IEEE802.15.4 device operations\n");
157 		return NULL;
158 	}
159 
160 	/* Ensure 32-byte alignment of our private data and hw private data.
161 	 * We use the wpan_phy priv data for both our ieee802154_local and for
162 	 * the driver's private data
163 	 *
164 	 * in memory it'll be like this:
165 	 *
166 	 * +-------------------------+
167 	 * | struct wpan_phy         |
168 	 * +-------------------------+
169 	 * | struct ieee802154_local |
170 	 * +-------------------------+
171 	 * | driver's private data   |
172 	 * +-------------------------+
173 	 *
174 	 * Due to ieee802154 layer isn't aware of driver and MAC structures,
175 	 * so lets align them here.
176 	 */
177 
178 	priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
179 
180 	phy = wpan_phy_alloc(priv_size);
181 	if (!phy) {
182 		pr_err("failure to allocate master IEEE802.15.4 device\n");
183 		return NULL;
184 	}
185 
186 	local = wpan_phy_priv(phy);
187 	local->phy = phy;
188 	local->hw.phy = local->phy;
189 	local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
190 	local->ops = ops;
191 
192 	INIT_LIST_HEAD(&local->interfaces);
193 	mutex_init(&local->iflist_mtx);
194 
195 	tasklet_init(&local->tasklet,
196 		     ieee802154_tasklet_handler,
197 		     (unsigned long)local);
198 
199 	skb_queue_head_init(&local->skb_queue);
200 
201 	return &local->hw;
202 }
203 EXPORT_SYMBOL(ieee802154_alloc_hw);
204 
205 void ieee802154_free_hw(struct ieee802154_hw *hw)
206 {
207 	struct ieee802154_local *local = hw_to_local(hw);
208 
209 	BUG_ON(!list_empty(&local->interfaces));
210 
211 	mutex_destroy(&local->iflist_mtx);
212 
213 	wpan_phy_free(local->phy);
214 }
215 EXPORT_SYMBOL(ieee802154_free_hw);
216 
217 int ieee802154_register_hw(struct ieee802154_hw *hw)
218 {
219 	struct ieee802154_local *local = hw_to_local(hw);
220 	int rc = -ENOSYS;
221 
222 	local->workqueue =
223 		create_singlethread_workqueue(wpan_phy_name(local->phy));
224 	if (!local->workqueue) {
225 		rc = -ENOMEM;
226 		goto out;
227 	}
228 
229 	wpan_phy_set_dev(local->phy, local->hw.parent);
230 
231 	local->phy->add_iface = mac802154_add_iface;
232 	local->phy->del_iface = mac802154_del_iface;
233 
234 	rc = wpan_phy_register(local->phy);
235 	if (rc < 0)
236 		goto out_wq;
237 
238 	rtnl_lock();
239 
240 	mutex_lock(&local->iflist_mtx);
241 	local->started = MAC802154_DEVICE_RUN;
242 	mutex_unlock(&local->iflist_mtx);
243 
244 	rtnl_unlock();
245 
246 	return 0;
247 
248 out_wq:
249 	destroy_workqueue(local->workqueue);
250 out:
251 	return rc;
252 }
253 EXPORT_SYMBOL(ieee802154_register_hw);
254 
255 void ieee802154_unregister_hw(struct ieee802154_hw *hw)
256 {
257 	struct ieee802154_local *local = hw_to_local(hw);
258 	struct ieee802154_sub_if_data *sdata, *next;
259 
260 	tasklet_kill(&local->tasklet);
261 	flush_workqueue(local->workqueue);
262 	destroy_workqueue(local->workqueue);
263 
264 	rtnl_lock();
265 
266 	mutex_lock(&local->iflist_mtx);
267 	local->started = MAC802154_DEVICE_STOPPED;
268 	mutex_unlock(&local->iflist_mtx);
269 
270 	list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
271 		mutex_lock(&sdata->local->iflist_mtx);
272 		list_del(&sdata->list);
273 		mutex_unlock(&sdata->local->iflist_mtx);
274 
275 		unregister_netdevice(sdata->dev);
276 	}
277 
278 	rtnl_unlock();
279 
280 	wpan_phy_unregister(local->phy);
281 }
282 EXPORT_SYMBOL(ieee802154_unregister_hw);
283 
284 MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
285 MODULE_LICENSE("GPL v2");
286