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