diff options
Diffstat (limited to 'net/mac802154/iface.c')
-rw-r--r-- | net/mac802154/iface.c | 66 |
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(); |