summaryrefslogtreecommitdiffstats
path: root/net/mac802154/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac802154/iface.c')
-rw-r--r--net/mac802154/iface.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
index 9d6012e430de..fced04b05275 100644
--- a/net/mac802154/iface.c
+++ b/net/mac802154/iface.c
@@ -444,6 +444,72 @@ void mac802154_monitor_setup(struct net_device *dev)
sdata->promisuous_mode = true;
}
+static int
+mac802154_netdev_register(struct ieee802154_local *local,
+ struct net_device *dev)
+{
+ struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+ int err;
+
+ sdata->dev = dev;
+ sdata->local = local;
+
+ dev->needed_headroom = local->hw.extra_tx_headroom;
+
+ SET_NETDEV_DEV(dev, &local->phy->dev);
+
+ err = register_netdev(dev);
+ if (err < 0)
+ return err;
+
+ rtnl_lock();
+ mutex_lock(&local->iflist_mtx);
+ list_add_tail_rcu(&sdata->list, &local->interfaces);
+ mutex_unlock(&local->iflist_mtx);
+ rtnl_unlock();
+
+ return 0;
+}
+
+struct net_device *
+ieee802154_if_add(struct ieee802154_local *local, const char *name,
+ struct wpan_dev **new_wpan_dev, int type)
+{
+ struct net_device *dev;
+ int err = -ENOMEM;
+
+ switch (type) {
+ case IEEE802154_DEV_MONITOR:
+ dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+ name, NET_NAME_UNKNOWN,
+ mac802154_monitor_setup);
+ break;
+ case IEEE802154_DEV_WPAN:
+ dev = alloc_netdev(sizeof(struct ieee802154_sub_if_data),
+ name, NET_NAME_UNKNOWN,
+ mac802154_wpan_setup);
+ break;
+ default:
+ dev = NULL;
+ err = -EINVAL;
+ break;
+ }
+ if (!dev)
+ goto err;
+
+ err = mac802154_netdev_register(local, dev);
+ if (err)
+ goto err_free;
+
+ dev_hold(dev); /* we return an incremented device refcount */
+ return dev;
+
+err_free:
+ free_netdev(dev);
+err:
+ return ERR_PTR(err);
+}
+
void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
{
ASSERT_RTNL();