diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 04a995dad593d0d3fcea6447d8a7d62121acdacb..3d40c23502617235e930dac6f23ec62615e4eddd 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 625d19e0a1defdc5b91f2944f272f936c67e223a..326baee227f76757122802e4dc8a3a5e17069a0c 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 8bd2785a663c93bd0eeb85727206113d24f5197a..521edcb0e586cb4cb69a4fd9cda8eccad9fabd66 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 47fc0c1bc3c7446d70fdf33b39b2a04b52b85d59..804e6c4f5f8a1fce6b2879c20391681dc6fe203d 100644 --- a/include/net/wpan-phy.h +++ b/include/net/wpan-phy.h @@ -47,6 +47,8 @@ struct wpan_phy { s8 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 d3ee62fbae99dd3be1c71a147271512c7282c6e7..f029310b066245fd96f42b5cdc48f3187d44c997 100644 --- a/net/ieee802154/nl-phy.c +++ b/net/ieee802154/nl-phy.c @@ -56,7 +56,8 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid, if (nla_put_string(msg, IEEE802154_ATTR_PHY_NAME, wpan_phy_name(phy)) || 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, phy->transmit_power)) + nla_put_s8(msg, IEEE802154_ATTR_TXPOWER, phy->transmit_power) || + 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]) @@ -356,40 +357,71 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info) 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; + + rc = phy->set_txpower(phy, txpower); + if (rc < 0) + return rc; + + phy->transmit_power = txpower; + + 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; - 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]); - 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; + if (info->attrs[IEEE802154_ATTR_LBT_ENABLED]) { + rc = phy_set_lbt(phy, info); + if (rc < 0) + goto error; + } mutex_unlock(&phy->pib_lock); @@ -397,6 +429,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 90b1d0d2c14e46b1420a88897775cf4841407e6c..a09f6423a6e9b8137cac7efab391e7cae79cd88a 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 9eb49e0886a4a54e1eae99a7bea08363b5dc6ca7..56338c8cfc3343580156211f58b6fbeebc422ef2 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)