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