ieee802154: rework interface registration
[deliverable/linux.git] / net / mac802154 / iface.c
index c0dbb402b99bdf15d57c3b8bcbb4ce395cc52e91..f9ed608aa26034e965c9f26607e13ee8abf1eddd 100644 (file)
 #include <net/cfg802154.h>
 
 #include "ieee802154_i.h"
+#include "driver-ops.h"
 
 static int mac802154_wpan_update_llsec(struct net_device *dev)
 {
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev);
        int rc = 0;
 
@@ -56,7 +57,7 @@ static int mac802154_wpan_update_llsec(struct net_device *dev)
 static int
 mac802154_wpan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct sockaddr_ieee802154 *sa =
                (struct sockaddr_ieee802154 *)&ifr->ifr_addr;
        int err = -ENOIOCTLCMD;
@@ -109,43 +110,68 @@ 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 */
+       extended_addr = ieee802154_netdev_to_extended_addr(addr->sa_data);
+       if (!ieee802154_is_valid_extended_addr(extended_addr))
+               return -EINVAL;
+
        memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-       mac802154_dev_set_ieee_addr(dev);
+       sdata->extended_addr = extended_addr;
+
        return mac802154_wpan_update_llsec(dev);
 }
 
-int mac802154_set_mac_params(struct net_device *dev,
-                            const struct ieee802154_mac_params *params)
+static int mac802154_slave_open(struct net_device *dev)
 {
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_sub_if_data *subif;
+       struct ieee802154_local *local = sdata->local;
+       int res = 0;
+
+       ASSERT_RTNL();
+
+       if (sdata->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 &&
+                           ieee802154_sdata_running(subif)) {
+                               mutex_unlock(&sdata->local->iflist_mtx);
+                               return -EBUSY;
+                       }
+               }
+               mutex_unlock(&sdata->local->iflist_mtx);
+       }
 
-       mutex_lock(&sdata->local->iflist_mtx);
-       sdata->mac_params = *params;
-       mutex_unlock(&sdata->local->iflist_mtx);
+       set_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       return 0;
-}
+       if (!local->open_count) {
+               res = drv_start(local);
+               WARN_ON(res);
+               if (res)
+                       goto err;
+       }
 
-void mac802154_get_mac_params(struct net_device *dev,
-                             struct ieee802154_mac_params *params)
-{
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       local->open_count++;
+       netif_start_queue(dev);
+       return 0;
+err:
+       /* might already be clear but that doesn't matter */
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
 
-       mutex_lock(&sdata->local->iflist_mtx);
-       *params = sdata->mac_params;
-       mutex_unlock(&sdata->local->iflist_mtx);
+       return res;
 }
 
 static int mac802154_wpan_open(struct net_device *dev)
 {
        int rc;
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
        struct wpan_phy *phy = sdata->local->phy;
 
        rc = mac802154_slave_open(dev);
@@ -154,41 +180,43 @@ static int mac802154_wpan_open(struct net_device *dev)
 
        mutex_lock(&phy->pib_lock);
 
-       if (phy->set_txpower) {
-               rc = phy->set_txpower(phy, sdata->mac_params.transmit_power);
+       if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
+               rc = drv_set_promiscuous_mode(local, sdata->promisuous_mode);
                if (rc < 0)
                        goto out;
        }
 
-       if (phy->set_lbt) {
-               rc = phy->set_lbt(phy, sdata->mac_params.lbt);
+       if (local->hw.flags & IEEE802154_HW_AFILT) {
+               rc = drv_set_pan_id(local, sdata->pan_id);
+               if (rc < 0)
+                       goto out;
+
+               rc = drv_set_extended_addr(local, sdata->extended_addr);
                if (rc < 0)
                        goto out;
-       }
 
-       if (phy->set_cca_mode) {
-               rc = phy->set_cca_mode(phy, sdata->mac_params.cca_mode);
+               rc = drv_set_short_addr(local, sdata->short_addr);
                if (rc < 0)
                        goto out;
        }
 
-       if (phy->set_cca_ed_level) {
-               rc = phy->set_cca_ed_level(phy, sdata->mac_params.cca_ed_level);
+       if (local->hw.flags & IEEE802154_HW_LBT) {
+               rc = drv_set_lbt_mode(local, sdata->mac_params.lbt);
                if (rc < 0)
                        goto out;
        }
 
-       if (phy->set_csma_params) {
-               rc = phy->set_csma_params(phy, sdata->mac_params.min_be,
-                                         sdata->mac_params.max_be,
-                                         sdata->mac_params.csma_retries);
+       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);
                if (rc < 0)
                        goto out;
        }
 
-       if (phy->set_frame_retries) {
-               rc = phy->set_frame_retries(phy,
-                                           sdata->mac_params.frame_retries);
+       if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
+               rc = drv_set_max_frame_retries(local,
+                                              sdata->mac_params.frame_retries);
                if (rc < 0)
                        goto out;
        }
@@ -201,6 +229,24 @@ out:
        return rc;
 }
 
+static int mac802154_slave_close(struct net_device *dev)
+{
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
+       struct ieee802154_local *local = sdata->local;
+
+       ASSERT_RTNL();
+
+       netif_stop_queue(dev);
+       local->open_count--;
+
+       clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+
+       if (!local->open_count)
+               drv_stop(local);
+
+       return 0;
+}
+
 static int mac802154_set_header_security(struct ieee802154_sub_if_data *sdata,
                                         struct ieee802154_hdr *hdr,
                                         const struct ieee802154_mac_cb *cb)
@@ -241,7 +287,7 @@ static int mac802154_header_create(struct sk_buff *skb,
                                   unsigned len)
 {
        struct ieee802154_hdr hdr;
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
        struct ieee802154_mac_cb *cb = mac_cb(skb);
        int hlen;
 
@@ -307,41 +353,6 @@ mac802154_header_parse(const struct sk_buff *skb, unsigned char *haddr)
        return sizeof(*addr);
 }
 
-static netdev_tx_t
-mac802154_wpan_xmit(struct sk_buff *skb, struct net_device *dev)
-{
-       struct ieee802154_sub_if_data *sdata;
-       u8 chan, page;
-       int rc;
-
-       sdata = netdev_priv(dev);
-
-       spin_lock_bh(&sdata->mib_lock);
-       chan = sdata->chan;
-       page = sdata->page;
-       spin_unlock_bh(&sdata->mib_lock);
-
-       if (chan == MAC802154_CHAN_NONE ||
-           page >= WPAN_NUM_PAGES ||
-           chan >= WPAN_NUM_CHANNELS) {
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       rc = mac802154_llsec_encrypt(&sdata->sec, skb);
-       if (rc) {
-               pr_warn("encryption failed: %i\n", rc);
-               kfree_skb(skb);
-               return NETDEV_TX_OK;
-       }
-
-       skb->skb_iif = dev->ifindex;
-       dev->stats.tx_packets++;
-       dev->stats.tx_bytes += skb->len;
-
-       return mac802154_tx(sdata->local, skb, page, chan);
-}
-
 static struct header_ops mac802154_header_ops = {
        .create         = mac802154_header_create,
        .parse          = mac802154_header_parse,
@@ -350,48 +361,43 @@ static struct header_ops mac802154_header_ops = {
 static const struct net_device_ops mac802154_wpan_ops = {
        .ndo_open               = mac802154_wpan_open,
        .ndo_stop               = mac802154_slave_close,
-       .ndo_start_xmit         = mac802154_wpan_xmit,
+       .ndo_start_xmit         = ieee802154_subif_start_xmit,
        .ndo_do_ioctl           = mac802154_wpan_ioctl,
        .ndo_set_mac_address    = mac802154_wpan_mac_addr,
 };
 
+static const struct net_device_ops mac802154_monitor_ops = {
+       .ndo_open               = mac802154_wpan_open,
+       .ndo_stop               = mac802154_slave_close,
+       .ndo_start_xmit         = ieee802154_monitor_start_xmit,
+};
+
 static void mac802154_wpan_free(struct net_device *dev)
 {
-       struct ieee802154_sub_if_data *sdata = netdev_priv(dev);
+       struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 
        mac802154_llsec_destroy(&sdata->sec);
 
        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->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->watchdog_timeo     = 0;
-
-       dev->destructor         = mac802154_wpan_free;
-       dev->netdev_ops         = &mac802154_wpan_ops;
-       dev->ml_priv            = &mac802154_mlme_wpan;
-
-       sdata = netdev_priv(dev);
-       sdata->type = IEEE802154_DEV_WPAN;
-
-       sdata->chan = MAC802154_CHAN_NONE;
-       sdata->page = 0;
+}
 
-       spin_lock_init(&sdata->mib_lock);
-       mutex_init(&sdata->sec_mtx);
+static int
+ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, int type)
+{
+       /* set some type-dependent values */
+       sdata->type = type;
 
        get_random_bytes(&sdata->bsn, 1);
        get_random_bytes(&sdata->dsn, 1);
@@ -406,191 +412,107 @@ void mac802154_wpan_setup(struct net_device *dev)
        sdata->pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
        sdata->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
 
-       mac802154_llsec_init(&sdata->sec);
-}
-
-static int mac802154_process_data(struct net_device *dev, struct sk_buff *skb)
-{
-       return netif_rx_ni(skb);
-}
-
-static int
-mac802154_subif_frame(struct ieee802154_sub_if_data *sdata, struct sk_buff *skb,
-                     const struct ieee802154_hdr *hdr)
-{
-       __le16 span, sshort;
-       int rc;
-
-       pr_debug("getting packet via slave interface %s\n", sdata->dev->name);
+       switch (type) {
+       case IEEE802154_DEV_WPAN:
+               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;
+               sdata->promisuous_mode = false;
 
-       spin_lock_bh(&sdata->mib_lock);
+               spin_lock_init(&sdata->mib_lock);
+               mutex_init(&sdata->sec_mtx);
 
-       span = sdata->pan_id;
-       sshort = sdata->short_addr;
-
-       switch (mac_cb(skb)->dest.mode) {
-       case IEEE802154_ADDR_NONE:
-               if (mac_cb(skb)->dest.mode != IEEE802154_ADDR_NONE)
-                       /* FIXME: check if we are PAN coordinator */
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else
-                       /* ACK comes with both addresses empty */
-                       skb->pkt_type = PACKET_HOST;
-               break;
-       case IEEE802154_ADDR_LONG:
-               if (mac_cb(skb)->dest.pan_id != span &&
-                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->dest.extended_addr == sdata->extended_addr)
-                       skb->pkt_type = PACKET_HOST;
-               else
-                       skb->pkt_type = PACKET_OTHERHOST;
+               mac802154_llsec_init(&sdata->sec);
                break;
-       case IEEE802154_ADDR_SHORT:
-               if (mac_cb(skb)->dest.pan_id != span &&
-                   mac_cb(skb)->dest.pan_id != cpu_to_le16(IEEE802154_PANID_BROADCAST))
-                       skb->pkt_type = PACKET_OTHERHOST;
-               else if (mac_cb(skb)->dest.short_addr == sshort)
-                       skb->pkt_type = PACKET_HOST;
-               else if (mac_cb(skb)->dest.short_addr ==
-                         cpu_to_le16(IEEE802154_ADDR_BROADCAST))
-                       skb->pkt_type = PACKET_BROADCAST;
-               else
-                       skb->pkt_type = PACKET_OTHERHOST;
+       case IEEE802154_DEV_MONITOR:
+               sdata->dev->destructor = free_netdev;
+               sdata->dev->netdev_ops = &mac802154_monitor_ops;
+               sdata->dev->ml_priv = &mac802154_mlme_reduced;
+               sdata->promisuous_mode = true;
                break;
        default:
-               spin_unlock_bh(&sdata->mib_lock);
-               pr_debug("invalid dest mode\n");
-               kfree_skb(skb);
-               return NET_RX_DROP;
+               BUG();
        }
 
-       spin_unlock_bh(&sdata->mib_lock);
-
-       skb->dev = sdata->dev;
-
-       rc = mac802154_llsec_decrypt(&sdata->sec, skb);
-       if (rc) {
-               pr_debug("decryption failed: %i\n", rc);
-               goto fail;
-       }
-
-       sdata->dev->stats.rx_packets++;
-       sdata->dev->stats.rx_bytes += skb->len;
-
-       switch (mac_cb(skb)->type) {
-       case IEEE802154_FC_TYPE_DATA:
-               return mac802154_process_data(sdata->dev, skb);
-       default:
-               pr_warn("ieee802154: bad frame received (type = %d)\n",
-                       mac_cb(skb)->type);
-               goto fail;
-       }
-
-fail:
-       kfree_skb(skb);
-       return NET_RX_DROP;
-}
-
-static void mac802154_print_addr(const char *name,
-                                const struct ieee802154_addr *addr)
-{
-       if (addr->mode == IEEE802154_ADDR_NONE)
-               pr_debug("%s not present\n", name);
-
-       pr_debug("%s PAN ID: %04x\n", name, le16_to_cpu(addr->pan_id));
-       if (addr->mode == IEEE802154_ADDR_SHORT) {
-               pr_debug("%s is short: %04x\n", name,
-                        le16_to_cpu(addr->short_addr));
-       } else {
-               u64 hw = swab64((__force u64) addr->extended_addr);
-
-               pr_debug("%s is hardware: %8phC\n", name, &hw);
-       }
+       return 0;
 }
 
-static int mac802154_parse_frame_start(struct sk_buff *skb,
-                                      struct ieee802154_hdr *hdr)
+struct net_device *
+ieee802154_if_add(struct ieee802154_local *local, const char *name,
+                 struct wpan_dev **new_wpan_dev, int type)
 {
-       int hlen;
-       struct ieee802154_mac_cb *cb = mac_cb_init(skb);
+       struct net_device *ndev = NULL;
+       struct ieee802154_sub_if_data *sdata = NULL;
+       int ret = -ENOMEM;
 
-       hlen = ieee802154_hdr_pull(skb, hdr);
-       if (hlen < 0)
-               return -EINVAL;
+       ASSERT_RTNL();
 
-       skb->mac_len = hlen;
+       ndev = alloc_netdev(sizeof(*sdata), name, NET_NAME_UNKNOWN,
+                           ieee802154_if_setup);
+       if (!ndev)
+               return ERR_PTR(-ENOMEM);
 
-       pr_debug("fc: %04x dsn: %02x\n", le16_to_cpup((__le16 *)&hdr->fc),
-                hdr->seq);
+       ndev->needed_headroom = local->hw.extra_tx_headroom;
 
-       cb->type = hdr->fc.type;
-       cb->ackreq = hdr->fc.ack_request;
-       cb->secen = hdr->fc.security_enabled;
+       ret = dev_alloc_name(ndev, ndev->name);
+       if (ret < 0)
+               goto err;
 
-       mac802154_print_addr("destination", &hdr->dest);
-       mac802154_print_addr("source", &hdr->source);
-
-       cb->source = hdr->source;
-       cb->dest = hdr->dest;
-
-       if (hdr->fc.security_enabled) {
-               u64 key;
+       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;
+       }
 
-               pr_debug("seclevel %i\n", hdr->sec.level);
+       /* 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;
+       }
 
-               switch (hdr->sec.key_id_mode) {
-               case IEEE802154_SCF_KEY_IMPLICIT:
-                       pr_debug("implicit key\n");
-                       break;
+       mutex_lock(&local->iflist_mtx);
+       list_add_tail_rcu(&sdata->list, &local->interfaces);
+       mutex_unlock(&local->iflist_mtx);
 
-               case IEEE802154_SCF_KEY_INDEX:
-                       pr_debug("key %02x\n", hdr->sec.key_id);
-                       break;
+       if (new_wpan_dev)
+               *new_wpan_dev = &sdata->wpan_dev;
 
-               case IEEE802154_SCF_KEY_SHORT_INDEX:
-                       pr_debug("key %04x:%04x %02x\n",
-                                le32_to_cpu(hdr->sec.short_src) >> 16,
-                                le32_to_cpu(hdr->sec.short_src) & 0xffff,
-                                hdr->sec.key_id);
-                       break;
+       return ndev;
 
-               case IEEE802154_SCF_KEY_HW_INDEX:
-                       key = swab64((__force u64) hdr->sec.extended_src);
-                       pr_debug("key source %8phC %02x\n", &key,
-                                hdr->sec.key_id);
-                       break;
-               }
-       }
-
-       return 0;
+err:
+       free_netdev(ndev);
+       return ERR_PTR(ret);
 }
 
-void mac802154_wpans_rx(struct ieee802154_local *local, struct sk_buff *skb)
+void ieee802154_if_remove(struct ieee802154_sub_if_data *sdata)
 {
-       int ret;
-       struct ieee802154_sub_if_data *sdata;
-       struct ieee802154_hdr hdr;
+       ASSERT_RTNL();
 
-       ret = mac802154_parse_frame_start(skb, &hdr);
-       if (ret) {
-               pr_debug("got invalid frame\n");
-               kfree_skb(skb);
-               return;
-       }
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               if (sdata->type != IEEE802154_DEV_WPAN ||
-                   !netif_running(sdata->dev))
-                       continue;
-
-               mac802154_subif_frame(sdata, skb, &hdr);
-               skb = NULL;
-               break;
-       }
-       rcu_read_unlock();
+       mutex_lock(&sdata->local->iflist_mtx);
+       list_del_rcu(&sdata->list);
+       mutex_unlock(&sdata->local->iflist_mtx);
 
-       if (skb)
-               kfree_skb(skb);
+       synchronize_rcu();
+       unregister_netdevice(sdata->dev);
 }
This page took 0.033288 seconds and 5 git commands to generate.