diff options
-rw-r--r-- | net/mac802154/ieee802154_dev.c | 142 | ||||
-rw-r--r-- | net/mac802154/mac802154.h | 3 |
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 | ||
35 | int 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; | ||
58 | err: | ||
59 | priv->hw->open_count--; | ||
60 | |||
61 | return res; | ||
62 | } | ||
63 | |||
64 | int 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 | |||
77 | static int | ||
78 | mac802154_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 | |||
114 | static void | ||
115 | mac802154_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 | |||
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 | /* 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 | |||
155 | err_free: | ||
156 | free_netdev(dev); | ||
157 | err: | ||
158 | return ERR_PTR(err); | ||
159 | } | ||
160 | |||
33 | struct ieee802154_dev * | 161 | struct ieee802154_dev * |
34 | ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops) | 162 | ieee802154_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); | |||
129 | void ieee802154_unregister_device(struct ieee802154_dev *dev) | 262 | void 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 | ||
93 | extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; | 93 | extern struct ieee802154_reduced_mlme_ops mac802154_mlme_reduced; |
94 | 94 | ||
95 | int mac802154_slave_open(struct net_device *dev); | ||
96 | int mac802154_slave_close(struct net_device *dev); | ||
97 | |||
95 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, | 98 | netdev_tx_t mac802154_tx(struct mac802154_priv *priv, struct sk_buff *skb, |
96 | u8 page, u8 chan); | 99 | u8 page, u8 chan); |
97 | 100 | ||