summaryrefslogtreecommitdiffstats
path: root/net/mac802154
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac802154')
-rw-r--r--net/mac802154/cfg.c26
-rw-r--r--net/mac802154/driver-ops.h5
-rw-r--r--net/mac802154/iface.c100
-rw-r--r--net/mac802154/mac_cmd.c6
4 files changed, 114 insertions, 23 deletions
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index c035708..5d9f68c 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -51,10 +51,7 @@ ieee802154_add_iface(struct wpan_phy *phy, const char *name,
struct net_device *err;
err = ieee802154_if_add(local, name, type, extended_addr);
- if (IS_ERR(err))
- return PTR_ERR(err);
-
- return 0;
+ return PTR_ERR_OR_ZERO(err);
}
static int
@@ -87,6 +84,26 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
}
static int
+ieee802154_set_cca_mode(struct wpan_phy *wpan_phy,
+ const struct wpan_phy_cca *cca)
+{
+ struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+ int ret;
+
+ ASSERT_RTNL();
+
+ /* check if phy support this setting */
+ if (!(local->hw.flags & IEEE802154_HW_CCA_MODE))
+ return -EOPNOTSUPP;
+
+ ret = drv_set_cca_mode(local, cca);
+ if (!ret)
+ wpan_phy->cca = *cca;
+
+ return ret;
+}
+
+static int
ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
__le16 pan_id)
{
@@ -201,6 +218,7 @@ const struct cfg802154_ops mac802154_config_ops = {
.add_virtual_intf = ieee802154_add_iface,
.del_virtual_intf = ieee802154_del_iface,
.set_channel = ieee802154_set_channel,
+ .set_cca_mode = ieee802154_set_cca_mode,
.set_pan_id = ieee802154_set_pan_id,
.set_short_addr = ieee802154_set_short_addr,
.set_backoff_exponent = ieee802154_set_backoff_exponent,
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h
index f21e864..98180a9 100644
--- a/net/mac802154/driver-ops.h
+++ b/net/mac802154/driver-ops.h
@@ -70,7 +70,8 @@ static inline int drv_set_tx_power(struct ieee802154_local *local, s8 dbm)
return local->ops->set_txpower(&local->hw, dbm);
}
-static inline int drv_set_cca_mode(struct ieee802154_local *local, u8 cca_mode)
+static inline int drv_set_cca_mode(struct ieee802154_local *local,
+ const struct wpan_phy_cca *cca)
{
might_sleep();
@@ -79,7 +80,7 @@ static inline int drv_set_cca_mode(struct ieee802154_local *local, u8 cca_mode)
return -EOPNOTSUPP;
}
- return local->ops->set_cca_mode(&local->hw, cca_mode);
+ return local->ops->set_cca_mode(&local->hw, cca);
}
static inline int drv_set_lbt_mode(struct ieee802154_local *local, bool mode)
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c
index 9ae8930..6fb6bdf 100644
--- a/net/mac802154/iface.c
+++ b/net/mac802154/iface.c
@@ -137,25 +137,11 @@ static int mac802154_wpan_mac_addr(struct net_device *dev, void *p)
static int mac802154_slave_open(struct net_device *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->vif.type == NL802154_IFTYPE_NODE) {
- mutex_lock(&sdata->local->iflist_mtx);
- list_for_each_entry(subif, &sdata->local->interfaces, list) {
- if (subif != sdata &&
- subif->vif.type == sdata->vif.type &&
- ieee802154_sdata_running(subif)) {
- mutex_unlock(&sdata->local->iflist_mtx);
- return -EBUSY;
- }
- }
- mutex_unlock(&sdata->local->iflist_mtx);
- }
-
set_bit(SDATA_STATE_RUNNING, &sdata->state);
if (!local->open_count) {
@@ -175,6 +161,88 @@ err:
return res;
}
+static int
+ieee802154_check_mac_settings(struct ieee802154_local *local,
+ struct wpan_dev *wpan_dev,
+ struct wpan_dev *nwpan_dev)
+{
+ ASSERT_RTNL();
+
+ if (local->hw.flags & IEEE802154_HW_PROMISCUOUS) {
+ if (wpan_dev->promiscuous_mode != nwpan_dev->promiscuous_mode)
+ return -EBUSY;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_AFILT) {
+ if (wpan_dev->pan_id != nwpan_dev->pan_id)
+ return -EBUSY;
+
+ if (wpan_dev->short_addr != nwpan_dev->short_addr)
+ return -EBUSY;
+
+ if (wpan_dev->extended_addr != nwpan_dev->extended_addr)
+ return -EBUSY;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) {
+ if (wpan_dev->min_be != nwpan_dev->min_be)
+ return -EBUSY;
+
+ if (wpan_dev->max_be != nwpan_dev->max_be)
+ return -EBUSY;
+
+ if (wpan_dev->csma_retries != nwpan_dev->csma_retries)
+ return -EBUSY;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_FRAME_RETRIES) {
+ if (wpan_dev->frame_retries != nwpan_dev->frame_retries)
+ return -EBUSY;
+ }
+
+ if (local->hw.flags & IEEE802154_HW_LBT) {
+ if (wpan_dev->lbt != nwpan_dev->lbt)
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+ieee802154_check_concurrent_iface(struct ieee802154_sub_if_data *sdata,
+ enum nl802154_iftype iftype)
+{
+ struct ieee802154_local *local = sdata->local;
+ struct wpan_dev *wpan_dev = &sdata->wpan_dev;
+ struct ieee802154_sub_if_data *nsdata;
+
+ /* we hold the RTNL here so can safely walk the list */
+ list_for_each_entry(nsdata, &local->interfaces, list) {
+ if (nsdata != sdata && ieee802154_sdata_running(nsdata)) {
+ int ret;
+
+ /* TODO currently we don't support multiple node types
+ * we need to run skb_clone at rx path. Check if there
+ * exist really an use case if we need to support
+ * multiple node types at the same time.
+ */
+ if (sdata->vif.type == NL802154_IFTYPE_NODE &&
+ nsdata->vif.type == NL802154_IFTYPE_NODE)
+ return -EBUSY;
+
+ /* check all phy mac sublayer settings are the same.
+ * We have only one phy, different values makes trouble.
+ */
+ ret = ieee802154_check_mac_settings(local, wpan_dev,
+ &nsdata->wpan_dev);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int mac802154_wpan_open(struct net_device *dev)
{
int rc;
@@ -183,6 +251,10 @@ static int mac802154_wpan_open(struct net_device *dev)
struct wpan_dev *wpan_dev = &sdata->wpan_dev;
struct wpan_phy *phy = sdata->local->phy;
+ rc = ieee802154_check_concurrent_iface(sdata, sdata->vif.type);
+ if (rc < 0)
+ return rc;
+
rc = mac802154_slave_open(dev);
if (rc < 0)
return rc;
diff --git a/net/mac802154/mac_cmd.c b/net/mac802154/mac_cmd.c
index 6aacb18..bdccb4e 100644
--- a/net/mac802154/mac_cmd.c
+++ b/net/mac802154/mac_cmd.c
@@ -81,7 +81,7 @@ static int mac802154_set_mac_params(struct net_device *dev,
/* PHY */
wpan_dev->wpan_phy->transmit_power = params->transmit_power;
- wpan_dev->wpan_phy->cca_mode = params->cca_mode;
+ wpan_dev->wpan_phy->cca = params->cca;
wpan_dev->wpan_phy->cca_ed_level = params->cca_ed_level;
/* MAC */
@@ -98,7 +98,7 @@ static int mac802154_set_mac_params(struct net_device *dev,
}
if (local->hw.flags & IEEE802154_HW_CCA_MODE) {
- ret = drv_set_cca_mode(local, params->cca_mode);
+ ret = drv_set_cca_mode(local, &params->cca);
if (ret < 0)
return ret;
}
@@ -122,7 +122,7 @@ static void mac802154_get_mac_params(struct net_device *dev,
/* PHY */
params->transmit_power = wpan_dev->wpan_phy->transmit_power;
- params->cca_mode = wpan_dev->wpan_phy->cca_mode;
+ params->cca = wpan_dev->wpan_phy->cca;
params->cca_ed_level = wpan_dev->wpan_phy->cca_ed_level;
/* MAC */
OpenPOWER on IntegriCloud