Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ieee802154_dev.c
Go to the documentation of this file.
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  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/netdevice.h>
26 
27 #include <net/netlink.h>
28 #include <linux/nl802154.h>
29 #include <net/mac802154.h>
30 #include <net/route.h>
31 #include <net/wpan-phy.h>
32 
33 #include "mac802154.h"
34 
36 {
37  struct mac802154_sub_if_data *priv = netdev_priv(dev);
38  struct mac802154_priv *ipriv = priv->hw;
39  int res = 0;
40 
41  if (ipriv->open_count++ == 0) {
42  res = ipriv->ops->start(&ipriv->hw);
43  WARN_ON(res);
44  if (res)
45  goto err;
46  }
47 
48  if (ipriv->ops->ieee_addr) {
49  res = ipriv->ops->ieee_addr(&ipriv->hw, dev->dev_addr);
50  WARN_ON(res);
51  if (res)
52  goto err;
54  }
55 
56  netif_start_queue(dev);
57  return 0;
58 err:
59  priv->hw->open_count--;
60 
61  return res;
62 }
63 
65 {
66  struct mac802154_sub_if_data *priv = netdev_priv(dev);
67  struct mac802154_priv *ipriv = priv->hw;
68 
69  netif_stop_queue(dev);
70 
71  if (!--ipriv->open_count)
72  ipriv->ops->stop(&ipriv->hw);
73 
74  return 0;
75 }
76 
77 static int
78 mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
79 {
81  struct mac802154_priv *ipriv;
82  int err;
83 
84  ipriv = wpan_phy_priv(phy);
85 
86  priv = netdev_priv(dev);
87  priv->dev = dev;
88  priv->hw = ipriv;
89 
90  dev->needed_headroom = ipriv->hw.extra_tx_headroom;
91 
92  SET_NETDEV_DEV(dev, &ipriv->phy->dev);
93 
94  mutex_lock(&ipriv->slaves_mtx);
95  if (!ipriv->running) {
96  mutex_unlock(&ipriv->slaves_mtx);
97  return -ENODEV;
98  }
99  mutex_unlock(&ipriv->slaves_mtx);
100 
101  err = register_netdev(dev);
102  if (err < 0)
103  return err;
104 
105  rtnl_lock();
106  mutex_lock(&ipriv->slaves_mtx);
107  list_add_tail_rcu(&priv->list, &ipriv->slaves);
108  mutex_unlock(&ipriv->slaves_mtx);
109  rtnl_unlock();
110 
111  return 0;
112 }
113 
114 static void
115 mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
116 {
118  ASSERT_RTNL();
119 
120  sdata = netdev_priv(dev);
121 
122  BUG_ON(sdata->hw->phy != phy);
123 
124  mutex_lock(&sdata->hw->slaves_mtx);
125  list_del_rcu(&sdata->list);
126  mutex_unlock(&sdata->hw->slaves_mtx);
127 
128  synchronize_rcu();
129  unregister_netdevice(sdata->dev);
130 }
131 
132 static struct net_device *
133 mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
134 {
135  struct net_device *dev;
136  int err = -ENOMEM;
137 
138  switch (type) {
140  dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
142  break;
143  case IEEE802154_DEV_WPAN:
144  dev = alloc_netdev(sizeof(struct mac802154_sub_if_data),
145  name, mac802154_wpan_setup);
146  break;
147  default:
148  dev = NULL;
149  err = -EINVAL;
150  break;
151  }
152  if (!dev)
153  goto err;
154 
155  err = mac802154_netdev_register(phy, dev);
156  if (err)
157  goto err_free;
158 
159  dev_hold(dev); /* we return an incremented device refcount */
160  return dev;
161 
162 err_free:
163  free_netdev(dev);
164 err:
165  return ERR_PTR(err);
166 }
167 
168 struct ieee802154_dev *
169 ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
170 {
171  struct wpan_phy *phy;
172  struct mac802154_priv *priv;
173  size_t priv_size;
174 
175  if (!ops || !ops->xmit || !ops->ed || !ops->start ||
176  !ops->stop || !ops->set_channel) {
178  "undefined IEEE802.15.4 device operations\n");
179  return NULL;
180  }
181 
182  /* Ensure 32-byte alignment of our private data and hw private data.
183  * We use the wpan_phy priv data for both our mac802154_priv and for
184  * the driver's private data
185  *
186  * in memory it'll be like this:
187  *
188  * +-----------------------+
189  * | struct wpan_phy |
190  * +-----------------------+
191  * | struct mac802154_priv |
192  * +-----------------------+
193  * | driver's private data |
194  * +-----------------------+
195  *
196  * Due to ieee802154 layer isn't aware of driver and MAC structures,
197  * so lets allign them here.
198  */
199 
200  priv_size = ALIGN(sizeof(*priv), NETDEV_ALIGN) + priv_data_len;
201 
202  phy = wpan_phy_alloc(priv_size);
203  if (!phy) {
205  "failure to allocate master IEEE802.15.4 device\n");
206  return NULL;
207  }
208 
209  priv = wpan_phy_priv(phy);
210  priv->hw.phy = priv->phy = phy;
211  priv->hw.priv = (char *)priv + ALIGN(sizeof(*priv), NETDEV_ALIGN);
212  priv->ops = ops;
213 
214  INIT_LIST_HEAD(&priv->slaves);
215  mutex_init(&priv->slaves_mtx);
216 
217  return &priv->hw;
218 }
220 
222 {
223  struct mac802154_priv *priv = mac802154_to_priv(hw);
224 
225  BUG_ON(!list_empty(&priv->slaves));
226 
227  wpan_phy_free(priv->phy);
228 
229  mutex_destroy(&priv->slaves_mtx);
230 }
232 
234 {
235  struct mac802154_priv *priv = mac802154_to_priv(dev);
236  int rc = -ENOMEM;
237 
238  priv->dev_workqueue =
239  create_singlethread_workqueue(wpan_phy_name(priv->phy));
240  if (!priv->dev_workqueue)
241  goto out;
242 
243  wpan_phy_set_dev(priv->phy, priv->hw.parent);
244 
245  priv->phy->add_iface = mac802154_add_iface;
246  priv->phy->del_iface = mac802154_del_iface;
247 
248  rc = wpan_phy_register(priv->phy);
249  if (rc < 0)
250  goto out_wq;
251 
252  rtnl_lock();
253 
254  mutex_lock(&priv->slaves_mtx);
256  mutex_unlock(&priv->slaves_mtx);
257 
258  rtnl_unlock();
259 
260  return 0;
261 
262 out_wq:
264 out:
265  return rc;
266 }
268 
270 {
271  struct mac802154_priv *priv = mac802154_to_priv(dev);
272  struct mac802154_sub_if_data *sdata, *next;
273 
276 
277  rtnl_lock();
278 
279  mutex_lock(&priv->slaves_mtx);
281  mutex_unlock(&priv->slaves_mtx);
282 
283  list_for_each_entry_safe(sdata, next, &priv->slaves, list) {
284  mutex_lock(&sdata->hw->slaves_mtx);
285  list_del(&sdata->list);
286  mutex_unlock(&sdata->hw->slaves_mtx);
287 
288  unregister_netdevice(sdata->dev);
289  }
290 
291  rtnl_unlock();
292 
293  wpan_phy_unregister(priv->phy);
294 }
296 
297 MODULE_DESCRIPTION("IEEE 802.15.4 implementation");
298 MODULE_LICENSE("GPL v2");