mac802154: add ifname change notifier
[deliverable/linux.git] / net / mac802154 / iface.c
index f7a6f83301e2096d679ccd6a2d65243c2921d591..ec92b48d1b0bfa40a7fafc148ff6f1d0bd9d3a1f 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <net/rtnetlink.h>
 #include <linux/nl802154.h>
-#include <net/af_ieee802154.h>
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
 #include <net/cfg802154.h>
@@ -36,16 +35,17 @@ static int mac802154_wpan_update_llsec(struct net_device *dev)
 {
        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
+       struct wpan_dev *wpan_dev = &sdata->wpan_dev;
        int rc = 0;
 
        if (ops->llsec) {
                struct ieee802154_llsec_params params;
                int changed = 0;
 
-               params.pan_id = sdata->pan_id;
+               params.pan_id = wpan_dev->pan_id;
                changed |= IEEE802154_LLSEC_PARAM_PAN_ID;
 
-               params.hwaddr = sdata->extended_addr;
+               params.hwaddr = wpan_dev->extended_addr;
                changed |= IEEE802154_LLSEC_PARAM_HWADDR;
 
                rc = ops->llsec->set_params(dev, &params, changed);
@@ -58,10 +58,13 @@ static int
 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct wpan_dev *wpan_dev = &sdata->wpan_dev;
        struct sockaddr_ieee802154 *sa =
                (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
        int err = -ENOIOCTLCMD;
 
+       ASSERT_RTNL();
+
        spin_lock_bh(&sdata->mib_lock);
 
        switch (cmd) {
@@ -69,8 +72,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        {
                u16 pan_id, short_addr;
 
-               pan_id = le16_to_cpu(sdata->pan_id);
-               short_addr = le16_to_cpu(sdata->short_addr);
+               pan_id = le16_to_cpu(wpan_dev->pan_id);
+               short_addr = le16_to_cpu(wpan_dev->short_addr);
                if (pan_id == IEEE802154_PANID_BROADCAST ||
                    short_addr == IEEE802154_ADDR_BROADCAST) {
                        err = -EADDRNOTAVAIL;
@@ -86,6 +89,11 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                break;
        }
        case SIOCSIFADDR:
+               if (netif_running(dev)) {
+                       spin_unlock_bh(&sdata->mib_lock);
+                       return -EBUSY;
+               }
+
                dev_warn(&dev->dev,
                         "Using DEBUGing ioctl SIOCSIFADDR isn't recommended!\n");
                if (sa->family != AF_IEEE802154 ||
@@ -97,8 +105,8 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        break;
                }
 
-               sdata->pan_id = cpu_to_le16(sa->addr.pan_id);
-               sdata->short_addr = cpu_to_le16(sa->addr.short_addr);
+               wpan_dev->pan_id = cpu_to_le16(sa->addr.pan_id);
+               wpan_dev->short_addr = cpu_to_le16(sa->addr.short_addr);
 
                err = mac802154_wpan_update_llsec(dev);
                break;
@@ -110,37 +118,21 @@ mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
 {
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct sockaddr *addr = p;
+       __le64 extended_addr;
 
        if (netif_running(dev))
                return -EBUSY;
 
-       /* FIXME: validate addr */
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       mac802154_dev_set_ieee_addr(dev);
-       return mac802154_wpan_update_llsec(dev);
-}
-
-int mac802154_set_mac_params(struct net_device *dev,
-                            const struct ieee802154_mac_params *params)
-{
-       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
-
-       mutex_lock(&sdata->local->iflist_mtx);
-       sdata->mac_params = *params;
-       mutex_unlock(&sdata->local->iflist_mtx);
-
-       return 0;
-}
+       ieee802154_be64_to_le64(&extended_addr, addr->sa_data);
+       if (!ieee802154_is_valid_extended_addr(extended_addr))
+               return -EINVAL;
 
-void mac802154_get_mac_params(struct net_device *dev,
-                             struct ieee802154_mac_params *params)
-{
-       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       sdata->wpan_dev.extended_addr = extended_addr;
 
-       mutex_lock(&sdata->local->iflist_mtx);
-       *params = sdata->mac_params;
-       mutex_unlock(&sdata->local->iflist_mtx);
+       return mac802154_wpan_update_llsec(dev);
 }
 
 static int mac802154_slave_open(struct net_device *dev)
@@ -152,10 +144,11 @@ static int mac802154_slave_open(struct net_device *dev)
 
        ASSERT_RTNL();
 
-       if (sdata->type == IEEE802154_DEV_WPAN) {
+       if (sdata->vif.type == IEEE802154_DEV_WPAN) {
                mutex_lock(&sdata->local->iflist_mtx);
                list_for_each_entry(subif, &sdata->local->interfaces, list) {
-                       if (subif != sdata && subif->type == sdata->type &&
+                       if (subif != sdata &&
+                           subif->vif.type == sdata->vif.type &&
                            ieee802154_sdata_running(subif)) {
                                mutex_unlock(&sdata->local->iflist_mtx);
                                return -EBUSY;
@@ -188,6 +181,7 @@ static int mac802154_wpan_open(struct net_device *dev)
        int rc;
        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct ieee802154_local *local = sdata->local;
+       struct wpan_dev *wpan_dev = &sdata->wpan_dev;
        struct wpan_phy *phy = sdata->local->phy;
 
        rc = mac802154_slave_open(dev);
@@ -197,47 +191,42 @@ static int mac802154_wpan_open(struct net_device *dev)
        mutex_lock(&phy->pib_lock);
 
        if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
-               rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode);
+               rc = drv_set_promiscuous_mode(local,
+                                             wpan_dev->promiscuous_mode);
                if (rc < 0)
                        goto out;
        }
 
-       if (local->hw.flags & IEEE802154_HW_TXPOWER) {
-               rc = drv_set_tx_power(local, sdata->mac_params.transmit_power);
+       if (local->hw.flags & IEEE802154_HW_AFILT) {
+               rc = drv_set_pan_id(local, wpan_dev->pan_id);
                if (rc < 0)
                        goto out;
-       }
 
-       if (local->hw.flags & IEEE802154_HW_LBT) {
-               rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
+               rc = drv_set_extended_addr(local, wpan_dev->extended_addr);
                if (rc < 0)
                        goto out;
-       }
 
-       if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
-               rc = drv_set_cca_mode(local, sdata->mac_params.cca_mode);
+               rc = drv_set_short_addr(local, wpan_dev->short_addr);
                if (rc < 0)
                        goto out;
        }
 
-       if (local->hw.flags & IEEE802154_HW_CCA_ED_LEVEL) {
-               rc = drv_set_cca_ed_level(local,
-                                         sdata->mac_params.cca_ed_level);
+       if (local->hw.flags & IEEE802154_HW_LBT) {
+               rc = drv_set_lbt_mode(local, wpan_dev->lbt);
                if (rc < 0)
                        goto out;
        }
 
        if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
-               rc = drv_set_csma_params(local, sdata->mac_params.min_be,
-                                        sdata->mac_params.max_be,
-                                        sdata->mac_params.csma_retries);
+               rc = drv_set_csma_params(local, wpan_dev->min_be,
+                                        wpan_dev->max_be,
+                                        wpan_dev->csma_retries);
                if (rc < 0)
                        goto out;
        }
 
        if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
-               rc = drv_set_max_frame_retries(local,
-                                              sdata->mac_params.frame_retries);
+               rc = drv_set_max_frame_retries(local, wpan_dev->frame_retries);
                if (rc < 0)
                        goto out;
        }
@@ -309,6 +298,7 @@ static int mac802154_header_create(struct sk_buff *skb,
 {
        struct ieee802154_hdr hdr;
        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct wpan_dev *wpan_dev = &sdata->wpan_dev;
        struct ieee802154_mac_cb *cb = mac_cb(skb);
        int hlen;
 
@@ -327,17 +317,17 @@ static int mac802154_header_create(struct sk_buff *skb,
        if (!saddr) {
                spin_lock_bh(&sdata->mib_lock);
 
-               if (sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
-                   sdata->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
-                   sdata->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
+               if (wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST) ||
+                   wpan_dev->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
+                   wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) {
                        hdr.source.mode = IEEE802154_ADDR_LONG;
-                       hdr.source.extended_addr = sdata->extended_addr;
+                       hdr.source.extended_addr = wpan_dev->extended_addr;
                } else {
                        hdr.source.mode = IEEE802154_ADDR_SHORT;
-                       hdr.source.short_addr = sdata->short_addr;
+                       hdr.source.short_addr = wpan_dev->short_addr;
                }
 
-               hdr.source.pan_id = sdata->pan_id;
+               hdr.source.pan_id = wpan_dev->pan_id;
 
                spin_unlock_bh(&sdata->mib_lock);
        } else {
@@ -402,65 +392,194 @@ static void mac802154_wpan_free(struct net_device *dev)
        free_netdev(dev);
 }
 
-void mac802154_wpan_setup(struct net_device *dev)
+static void ieee802154_if_setup(struct net_device *dev)
 {
-       struct ieee802154_sub_if_data *sdata;
-
-       dev->addr_len           = IEEE802154_ADDR_LEN;
-       memset(dev->broadcast, 0xff, IEEE802154_ADDR_LEN);
+       dev->addr_len           = IEEE802154_EXTENDED_ADDR_LEN;
+       memset(dev->broadcast, 0xff, IEEE802154_EXTENDED_ADDR_LEN);
 
        dev->hard_header_len    = MAC802154_FRAME_HARD_HEADER_LEN;
-       dev->header_ops         = &mac802154_header_ops;
        dev->needed_tailroom    = 2 + 16; /* FCS + MIC */
        dev->mtu                = IEEE802154_MTU;
        dev->tx_queue_len       = 300;
-       dev->type               = ARPHRD_IEEE802154;
        dev->flags              = IFF_NOARP | IFF_BROADCAST;
+}
 
-       dev->destructor         = mac802154_wpan_free;
-       dev->netdev_ops         = &mac802154_wpan_ops;
-       dev->ml_priv            = &mac802154_mlme_wpan;
-
-       sdata = IEEE802154_DEV_TO_SUB_IF(dev);
-       sdata->type = IEEE802154_DEV_WPAN;
+static int
+ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, int type)
+{
+       struct wpan_dev *wpan_dev = &sdata->wpan_dev;
 
-       spin_lock_init(&sdata->mib_lock);
-       mutex_init(&sdata->sec_mtx);
+       /* set some type-dependent values */
+       sdata->vif.type = type;
+       sdata->wpan_dev.iftype = type;
 
-       get_random_bytes(&sdata->bsn, 1);
-       get_random_bytes(&sdata->dsn, 1);
+       get_random_bytes(&wpan_dev->bsn, 1);
+       get_random_bytes(&wpan_dev->dsn, 1);
 
        /* defaults per 802.15.4-2011 */
-       sdata->mac_params.min_be = 3;
-       sdata->mac_params.max_be = 5;
-       sdata->mac_params.csma_retries = 4;
+       wpan_dev->min_be = 3;
+       wpan_dev->max_be = 5;
+       wpan_dev->csma_retries = 4;
        /* for compatibility, actual default is 3 */
-       sdata->mac_params.frame_retries = -1;
+       wpan_dev->frame_retries = -1;
+
+       wpan_dev->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+       wpan_dev->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
 
-       sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
-       sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+       switch (type) {
+       case IEEE802154_DEV_WPAN:
+               ieee802154_be64_to_le64(&wpan_dev->extended_addr,
+                                       sdata->dev->dev_addr);
 
-       sdata->promisuous_mode = false;
+               sdata->dev->header_ops = &mac802154_header_ops;
+               sdata->dev->destructor = mac802154_wpan_free;
+               sdata->dev->netdev_ops = &mac802154_wpan_ops;
+               sdata->dev->ml_priv = &mac802154_mlme_wpan;
+               wpan_dev->promiscuous_mode = false;
 
-       mac802154_llsec_init(&sdata->sec);
+               spin_lock_init(&sdata->mib_lock);
+               mutex_init(&sdata->sec_mtx);
+
+               mac802154_llsec_init(&sdata->sec);
+               break;
+       case IEEE802154_DEV_MONITOR:
+               sdata->dev->destructor = free_netdev;
+               sdata->dev->netdev_ops = &mac802154_monitor_ops;
+               wpan_dev->promiscuous_mode = true;
+               break;
+       default:
+               BUG();
+       }
+
+       return 0;
 }
 
-void mac802154_monitor_setup(struct net_device *dev)
+struct net_device *
+ieee802154_if_add(struct ieee802154_local *local, const char *name,
+                 struct wpan_dev **new_wpan_dev, int type)
 {
+       struct net_device *ndev = NULL;
+       struct ieee802154_sub_if_data *sdata = NULL;
+       int ret = -ENOMEM;
+
+       ASSERT_RTNL();
+
+       ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, name,
+                           NET_NAME_UNKNOWN, ieee802154_if_setup);
+       if (!ndev)
+               return ERR_PTR(-ENOMEM);
+
+       ndev->needed_headroom = local->hw.extra_tx_headroom;
+
+       ret = dev_alloc_name(ndev, ndev->name);
+       if (ret < 0)
+               goto err;
+
+       switch (type) {
+       case IEEE802154_DEV_WPAN:
+               ndev->type = ARPHRD_IEEE802154;
+               break;
+       case IEEE802154_DEV_MONITOR:
+               ndev->type = ARPHRD_IEEE802154_MONITOR;
+               break;
+       default:
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ieee802154_le64_to_be64(ndev->perm_addr,
+                               &local->hw.phy->perm_extended_addr);
+       memcpy(ndev->dev_addr, ndev->perm_addr, IEEE802154_EXTENDED_ADDR_LEN);
+       /* TODO check this */
+       SET_NETDEV_DEV(ndev, &local->phy->dev);
+       sdata = netdev_priv(ndev);
+       ndev->ieee802154_ptr = &sdata->wpan_dev;
+       memcpy(sdata->name, ndev->name, IFNAMSIZ);
+       sdata->dev = ndev;
+       sdata->wpan_dev.wpan_phy = local->hw.phy;
+       sdata->local = local;
+
+       /* setup type-dependent data */
+       ret = ieee802154_setup_sdata(sdata, type);
+       if (ret)
+               goto err;
+
+       if (ndev) {
+               ret = register_netdevice(ndev);
+               if (ret < 0)
+                       goto err;
+       }
+
+       mutex_lock(&local->iflist_mtx);
+       list_add_tail_rcu(&sdata->list, &local->interfaces);
+       mutex_unlock(&local->iflist_mtx);
+
+       if (new_wpan_dev)
+               *new_wpan_dev = &sdata->wpan_dev;
+
+       return ndev;
+
+err:
+       free_netdev(ndev);
+       return ERR_PTR(ret);
+}
+
+void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
+{
+       ASSERT_RTNL();
+
+       mutex_lock(&sdata->local->iflist_mtx);
+       list_del_rcu(&sdata->list);
+       mutex_unlock(&sdata->local->iflist_mtx);
+
+       synchronize_rcu();
+       unregister_netdevice(sdata->dev);
+}
+
+void ieee802154_remove_interfaces(struct ieee802154_local *local)
+{
+       struct ieee802154_sub_if_data *sdata, *tmp;
+
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
+               list_del(&sdata->list);
+
+               unregister_netdevice(sdata->dev);
+       }
+       mutex_unlock(&local->iflist_mtx);
+}
+
+static int netdev_notify(struct notifier_block *nb,
+                        unsigned long state, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
        struct ieee802154_sub_if_data *sdata;
 
-       dev->needed_tailroom    = 2; /* room for FCS */
-       dev->mtu                = IEEE802154_MTU;
-       dev->tx_queue_len       = 10;
-       dev->type               = ARPHRD_IEEE802154_MONITOR;
-       dev->flags              = IFF_NOARP | IFF_BROADCAST;
+       if (state != NETDEV_CHANGENAME)
+               return NOTIFY_DONE;
+
+       if (!dev->ieee802154_ptr || !dev->ieee802154_ptr->wpan_phy)
+               return NOTIFY_DONE;
 
-       dev->destructor         = free_netdev;
-       dev->netdev_ops         = &mac802154_monitor_ops;
-       dev->ml_priv            = &mac802154_mlme_reduced;
+       if (dev->ieee802154_ptr->wpan_phy->privid != mac802154_wpan_phy_privid)
+               return NOTIFY_DONE;
 
        sdata = IEEE802154_DEV_TO_SUB_IF(dev);
-       sdata->type = IEEE802154_DEV_MONITOR;
+       memcpy(sdata->name, dev->name, IFNAMSIZ);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block mac802154_netdev_notifier = {
+       .notifier_call = netdev_notify,
+};
 
-       sdata->promisuous_mode = true;
+int ieee802154_iface_init(void)
+{
+       return register_netdevice_notifier(&mac802154_netdev_notifier);
+}
+
+void ieee802154_iface_exit(void)
+{
+       unregister_netdevice_notifier(&mac802154_netdev_notifier);
 }
This page took 0.036021 seconds and 5 git commands to generate.