aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac802154/ieee802154_dev.c142
-rw-r--r--net/mac802154/mac802154.h3
2 files changed, 145 insertions, 0 deletions
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
index d130271eb528..9f36760b6c3a 100644
--- a/net/mac802154/ieee802154_dev.c
+++ b/net/mac802154/ieee802154_dev.c
@@ -24,12 +24,140 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/netdevice.h> 25#include <linux/netdevice.h>
26 26
27#include <net/netlink.h>
28#include <linux/nl802154.h>
27#include <net/mac802154.h> 29#include <net/mac802154.h>
28#include <net/route.h> 30#include <net/route.h>
29#include <net/wpan-phy.h> 31#include <net/wpan-phy.h>
30 32
31#include "mac802154.h" 33#include "mac802154.h"
32 34
35int mac802154_slave_open(struct net_device *dev)
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;
53 mac802154_dev_set_ieee_addr(dev);
54 }
55
56 netif_start_queue(dev);
57 return 0;
58err:
59 priv->hw->open_count--;
60
61 return res;
62}
63
64int mac802154_slave_close(struct net_device *dev)
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
77static int
78mac802154_netdev_register(struct wpan_phy *phy, struct net_device *dev)
79{
80 struct mac802154_sub_if_data *priv;
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
114static void
115mac802154_del_iface(struct wpan_phy *phy, struct net_device *dev)
116{
117 struct mac802154_sub_if_data *sdata;
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
132static struct net_device *
133mac802154_add_iface(struct wpan_phy *phy, const char *name, int type)
134{
135 struct net_device *dev;
136 int err = -ENOMEM;
137
138 /* No devices is currently added */
139 switch (type) {
140 default:
141 dev = NULL;
142 err = -EINVAL;
143 break;
144 }
145 if (!dev)
146 goto err;
147
148 err = mac802154_netdev_register(phy, dev);
149 if (err)
150 goto err_free;
151
152 dev_hold(dev); /* we return an incremented device refcount */
153 return dev;
154
155err_free:
156 free_netdev(dev);
157err:
158 return ERR_PTR(err);
159}
160
33struct ieee802154_dev * 161struct ieee802154_dev *
34ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) 162ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
35{ 163{
@@ -87,6 +215,8 @@ void ieee802154_free_device(struct ieee802154_dev *hw)
87{ 215{
88 struct mac802154_priv *priv = mac802154_to_priv(hw); 216 struct mac802154_priv *priv = mac802154_to_priv(hw);
89 217
218 BUG_ON(!list_empty(&priv->slaves));
219
90 wpan_phy_free(priv->phy); 220 wpan_phy_free(priv->phy);
91 221
92 mutex_destroy(&priv->slaves_mtx); 222 mutex_destroy(&priv->slaves_mtx);
@@ -105,6 +235,9 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
105 235
106 wpan_phy_set_dev(priv->phy, priv->hw.parent); 236 wpan_phy_set_dev(priv->phy, priv->hw.parent);
107 237
238 priv->phy->add_iface = mac802154_add_iface;
239 priv->phy->del_iface = mac802154_del_iface;
240
108 rc = wpan_phy_register(priv->phy); 241 rc = wpan_phy_register(priv->phy);
109 if (rc < 0) 242 if (rc < 0)
110 goto out_wq; 243 goto out_wq;
@@ -129,6 +262,7 @@ EXPORT_SYMBOL(ieee802154_register_device);
129void ieee802154_unregister_device(struct ieee802154_dev *dev) 262void ieee802154_unregister_device(struct ieee802154_dev *dev)
130{ 263{
131 struct mac802154_priv *priv = mac802154_to_priv(dev); 264 struct mac802154_priv *priv = mac802154_to_priv(dev);
265 struct mac802154_sub_if_data *sdata, *next;
132 266
133 flush_workqueue(priv->dev_workqueue); 267 flush_workqueue(priv->dev_workqueue);
134 destroy_workqueue(priv->dev_workqueue); 268 destroy_workqueue(priv->dev_workqueue);
@@ -139,6 +273,14 @@ void ieee802154_unregister_device(struct ieee802154_dev *dev)
139 priv->running = MAC802154_DEVICE_STOPPED; 273 priv->running = MAC802154_DEVICE_STOPPED;
140 mutex_unlock(&priv->slaves_mtx); 274 mutex_unlock(&priv->slaves_mtx);
141 275
276 list_for_each_entry_safe(sdata, next, &priv->slaves, list) {
277 mutex_lock(&sdata->hw->slaves_mtx);
278 list_del(&sdata->list);
279 mutex_unlock(&sdata->hw->slaves_mtx);
280
281 unregister_netdevice(sdata->dev);
282 }
283
142 rtnl_unlock(); 284 rtnl_unlock();
143 285
144 wpan_phy_unregister(priv->phy); 286 wpan_phy_unregister(priv->phy);
diff --git a/net/mac802154/mac802154.h b/net/mac802154/mac802154.h
index 7d9a0d4a99fd..622752622c87 100644
--- a/net/mac802154/mac802154.h
+++ b/net/mac802154/mac802154.h
@@ -92,6 +92,9 @@ struct mac802154_sub_if_data {
92 92
93extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; 93extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced;
94 94
95int mac802154_slave_open(struct net_device *dev);
96int mac802154_slave_close(struct net_device *dev);
97
95netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, 98netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb,
96 u8 page, u8 chan); 99 u8 page, u8 chan);
97 100