]> Git Repo - linux.git/blob - net/mac802154/main.c
net: systemport: log RX buffer allocation and RX/TX DMA failures
[linux.git] / net / mac802154 / main.c
1 /*
2  * Copyright (C) 2007-2012 Siemens AG
3  *
4  * Written by:
5  * Alexander Smirnov <[email protected]>
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 static int
33 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
34 {
35         struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
36         struct ieee802154_local *local;
37         int err;
38
39         local = wpan_phy_priv(phy);
40
41         sdata->dev = dev;
42         sdata->local = local;
43
44         dev->needed_headroom = local->hw.extra_tx_headroom;
45
46         SET_NETDEV_DEV(dev, &local->phy->dev);
47
48         err = register_netdev(dev);
49         if (err < 0)
50                 return err;
51
52         rtnl_lock();
53         mutex_lock(&local->iflist_mtx);
54         list_add_tail_rcu(&sdata->list, &local->interfaces);
55         mutex_unlock(&local->iflist_mtx);
56         rtnl_unlock();
57
58         return 0;
59 }
60
61 static void
62 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 static 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(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         local->phy->add_iface = mac802154_add_iface;
224         local->phy->del_iface = mac802154_del_iface;
225
226         rc = wpan_phy_register(local->phy);
227         if (rc < 0)
228                 goto out_wq;
229
230         return 0;
231
232 out_wq:
233         destroy_workqueue(local->workqueue);
234 out:
235         return rc;
236 }
237 EXPORT_SYMBOL(ieee802154_register_hw);
238
239 void ieee802154_unregister_hw(struct ieee802154_hw *hw)
240 {
241         struct ieee802154_local *local = hw_to_local(hw);
242         struct ieee802154_sub_if_data *sdata, *next;
243
244         tasklet_kill(&local->tasklet);
245         flush_workqueue(local->workqueue);
246         destroy_workqueue(local->workqueue);
247
248         rtnl_lock();
249
250         list_for_each_entry_safe(sdata, next, &local->interfaces, list) {
251                 mutex_lock(&sdata->local->iflist_mtx);
252                 list_del(&sdata->list);
253                 mutex_unlock(&sdata->local->iflist_mtx);
254
255                 unregister_netdevice(sdata->dev);
256         }
257
258         rtnl_unlock();
259
260         wpan_phy_unregister(local->phy);
261 }
262 EXPORT_SYMBOL(ieee802154_unregister_hw);
263
264 MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
265 MODULE_LICENSE("GPL v2");
This page took 0.05077 seconds and 4 git commands to generate.