Listen-before-talk is an alternative to CSMA in uncoordinated networks
and prescribed by european regulations if one wants to have a device
with radio duty cycles above 10% (or less in some bands). Add a phy
property to enable/disable LBT in the phy, including support in the
at86rf230 driver for RF212 chips.

Signed-off-by: Phoebe Buckheister <phoebe.buckheis...@itwm.fraunhofer.de>
---
 drivers/net/ieee802154/at86rf230.c |   11 +++++-
 include/linux/nl802154.h           |    1 +
 include/net/mac802154.h            |    6 ++++
 include/net/wpan-phy.h             |    3 ++
 net/ieee802154/nl-phy.c            |   69 +++++++++++++++++++++++++++---------
 net/ieee802154/nl_policy.c         |    1 +
 net/mac802154/ieee802154_dev.c     |   11 ++++++
 7 files changed, 84 insertions(+), 18 deletions(-)

diff --git a/drivers/net/ieee802154/at86rf230.c 
b/drivers/net/ieee802154/at86rf230.c
index 3a8b831..973811b 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -152,7 +152,7 @@ static inline int is_rf212(struct at86rf230_local *local)
 #define        SR_RESERVED_17_5        0x17, 0x08, 3
 #define        SR_AACK_UPLD_RES_FT     0x17, 0x10, 4
 #define        SR_AACK_FLTR_RES_FT     0x17, 0x20, 5
-#define        SR_RESERVED_17_2        0x17, 0x40, 6
+#define        SR_CSMA_LBT_MODE        0x17, 0x40, 6
 #define        SR_RESERVED_17_1        0x17, 0x80, 7
 #define        RG_FTN_CTRL     (0x18)
 #define        SR_RESERVED_18_2        0x18, 0x7f, 0
@@ -786,6 +786,14 @@ at86rf212_set_txpower(struct ieee802154_dev *dev, int db)
        return 0;
 }
 
+static int
+at86rf212_set_lbt(struct ieee802154_dev *dev, bool on)
+{
+       struct at86rf230_local *lp = dev->priv;
+
+       return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on);
+}
+
 static struct ieee802154_ops at86rf230_ops = {
        .owner = THIS_MODULE,
        .xmit = at86rf230_xmit,
@@ -805,6 +813,7 @@ static struct ieee802154_ops at86rf212_ops = {
        .stop = at86rf230_stop,
        .set_hw_addr_filt = at86rf230_set_hw_addr_filt,
        .set_txpower = at86rf212_set_txpower,
+       .set_lbt = at86rf212_set_lbt,
 };
 
 static void at86rf230_irqwork(struct work_struct *work)
diff --git a/include/linux/nl802154.h b/include/linux/nl802154.h
index 625d19e..326baee 100644
--- a/include/linux/nl802154.h
+++ b/include/linux/nl802154.h
@@ -71,6 +71,7 @@ enum {
        IEEE802154_ATTR_DEV_TYPE,
 
        IEEE802154_ATTR_TXPOWER,
+       IEEE802154_ATTR_LBT_ENABLED,
 
        __IEEE802154_ATTR_MAX,
 };
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 8bd2785..521edcb 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -117,6 +117,11 @@ struct ieee802154_dev {
  * set_txpower:
  *       Set radio transmit power in dB. Called with pib_lock held.
  *       Returns either zero, or negative errno.
+ *
+ * set_lbt
+ *       Enables or disables listen before talk on the device. Called with
+ *       pib_lock held.
+ *       Returns either zero, or negative errno.
  */
 struct ieee802154_ops {
        struct module   *owner;
@@ -134,6 +139,7 @@ struct ieee802154_ops {
        int             (*ieee_addr)(struct ieee802154_dev *dev,
                                     u8 addr[IEEE802154_ADDR_LEN]);
        int             (*set_txpower)(struct ieee802154_dev *dev, int db);
+       int             (*set_lbt)(struct ieee802154_dev *dev, bool on);
 };
 
 /* Basic interface to register ieee802154 device */
diff --git a/include/net/wpan-phy.h b/include/net/wpan-phy.h
index f06c272..e87b613 100644
--- a/include/net/wpan-phy.h
+++ b/include/net/wpan-phy.h
@@ -47,6 +47,8 @@ struct wpan_phy {
        u8 transmit_power;
        u8 cca_mode;
 
+       bool lbt;
+
        struct device dev;
        int idx;
 
@@ -55,6 +57,7 @@ struct wpan_phy {
        void (*del_iface)(struct wpan_phy *phy, struct net_device *dev);
 
        int (*set_txpower)(struct wpan_phy *phy, int db);
+       int (*set_lbt)(struct wpan_phy *phy, bool on);
 
        char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
 };
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index 14bc270..d73ae97 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -57,7 +57,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 
portid,
            nla_put_u8(msg, IEEE802154_ATTR_PAGE, phy->current_page) ||
            nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel) ||
            nla_put_s8(msg, IEEE802154_ATTR_TXPOWER,
-                               ((signed char) (phy->transmit_power << 2)) >> 
2))
+                               ((signed char) (phy->transmit_power << 2)) >> 
2) ||
+           nla_put_u8(msg, IEEE802154_ATTR_LBT_ENABLED, phy->lbt))
                goto nla_put_failure;
        for (i = 0; i < 32; i++) {
                if (phy->channels_supported[i])
@@ -357,45 +358,77 @@ out_dev:
        return rc;
 }
 
+static int phy_set_txpower(struct wpan_phy *phy, struct genl_info *info)
+{
+       int txpower = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
+       int rc;
+       u8 txpower_wpan;
+
+       if (txpower < -64 || txpower > 63)
+               return -EINVAL; /* txpower code subfield is 6 bits long */
+
+       txpower_wpan = ((unsigned char) (txpower << 2)) >> 2;
+
+       rc = phy->set_txpower(phy, txpower);
+       if (rc < 0)
+               return rc;
+
+       phy->transmit_power = txpower_wpan;
+
+       return 0;
+}
+
+static int phy_set_lbt(struct wpan_phy *phy, struct genl_info *info)
+{
+       u8 on = !!nla_get_u8(info->attrs[IEEE802154_ATTR_LBT_ENABLED]);
+       int rc;
+
+       rc = phy->set_lbt(phy, on);
+       if (rc < 0)
+               return rc;
+
+       phy->lbt = on;
+       
+       return 0;
+}
+
 int ieee802154_set_phyparams(struct sk_buff *skb, struct genl_info *info)
 {
        struct wpan_phy *phy;
        const char *name;
-       int txpower;
-       u8 txpower_wpan;
-       int rc = -EINVAL;
+       int rc = -ENOTSUPP;
 
        pr_debug("%s\n", __func__);
 
-       if (!info->attrs[IEEE802154_ATTR_PHY_NAME])
+       if (!info->attrs[IEEE802154_ATTR_PHY_NAME] &&
+               !info->attrs[IEEE802154_ATTR_LBT_ENABLED])
                return -EINVAL;
 
        name = nla_data(info->attrs[IEEE802154_ATTR_PHY_NAME]);
        if (name[nla_len(info->attrs[IEEE802154_ATTR_PHY_NAME]) - 1] != '\0')
                return -EINVAL; /* phy name should be null-terminated */
 
-       txpower = nla_get_s8(info->attrs[IEEE802154_ATTR_TXPOWER]);
-       if (txpower < -64 || txpower > 63)
-               return -EINVAL; /* txpower code subfield is 6 bits long */
-
-       txpower_wpan = ((unsigned char) (txpower << 2)) >> 2;
-
        phy = wpan_phy_find(name);
        if (!phy)
                return -ENODEV;
 
-       if (!phy->set_txpower)
+       if ((!phy->set_txpower && info->attrs[IEEE802154_ATTR_TXPOWER]) ||
+               (!phy->set_lbt && info->attrs[IEEE802154_ATTR_LBT_ENABLED]))
                goto out;
 
        mutex_lock(&phy->pib_lock);
 
-       rc = phy->set_txpower(phy, txpower);
-       if (rc < 0) {
-               mutex_unlock(&phy->pib_lock);
-               goto out;
+       if (info->attrs[IEEE802154_ATTR_TXPOWER]) {
+               rc = phy_set_txpower(phy, info);
+               if (rc < 0)
+                       goto error;
        }
 
-       phy->transmit_power = txpower_wpan;
+       if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) {
+               rc = phy_set_lbt(phy, info);
+               if (rc < 0)
+                       goto error;
+       }
 
        mutex_unlock(&phy->pib_lock);
 
@@ -403,6 +436,8 @@ int ieee802154_set_phyparams(struct sk_buff *skb, struct 
genl_info *info)
 
        return 0;
 
+error:
+       mutex_unlock(&phy->pib_lock);
 out:
        wpan_phy_put(phy);
        return rc;
diff --git a/net/ieee802154/nl_policy.c b/net/ieee802154/nl_policy.c
index 90b1d0d..a09f642 100644
--- a/net/ieee802154/nl_policy.c
+++ b/net/ieee802154/nl_policy.c
@@ -54,5 +54,6 @@ const struct nla_policy ieee802154_policy[IEEE802154_ATTR_MAX 
+ 1] = {
        [IEEE802154_ATTR_CHANNEL_PAGE_LIST] = { .len = 32 * 4, },
 
        [IEEE802154_ATTR_TXPOWER] = { .type = NLA_S8, },
+       [IEEE802154_ATTR_LBT_ENABLED] = { .type = NLA_U8, },
 };
 
diff --git a/net/mac802154/ieee802154_dev.c b/net/mac802154/ieee802154_dev.c
index 9eb49e0..56338c8 100644
--- a/net/mac802154/ieee802154_dev.c
+++ b/net/mac802154/ieee802154_dev.c
@@ -175,6 +175,16 @@ static int mac802154_set_txpower(struct wpan_phy *phy, int 
db)
        return priv->ops->set_txpower(&priv->hw, db);
 }
 
+static int mac802154_set_lbt(struct wpan_phy *phy, bool on)
+{
+       struct mac802154_priv *priv = wpan_phy_priv(phy);
+
+       if (!priv->ops->set_lbt)
+               return -ENOTSUPP;
+
+       return priv->ops->set_lbt(&priv->hw, on);
+}
+
 struct ieee802154_dev *
 ieee802154_alloc_device(size_t priv_data_len, struct ieee802154_ops *ops)
 {
@@ -253,6 +263,7 @@ int ieee802154_register_device(struct ieee802154_dev *dev)
        priv->phy->add_iface = mac802154_add_iface;
        priv->phy->del_iface = mac802154_del_iface;
        priv->phy->set_txpower = mac802154_set_txpower;
+       priv->phy->set_lbt = mac802154_set_lbt;
 
        rc = wpan_phy_register(priv->phy);
        if (rc < 0)
-- 
1.7.9.5


------------------------------------------------------------------------------
WatchGuard Dimension instantly turns raw network data into actionable 
security intelligence. It gives you real-time visual feedback on key
security issues and trends.  Skip the complicated setup - simply import
a virtual appliance and go from zero to informed in seconds.
http://pubads.g.doubleclick.net/gampad/clk?id=123612991&iu=/4140/ostg.clktrk
_______________________________________________
Linux-zigbee-devel mailing list
Linux-zigbee-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel

Reply via email to