Hello,
Here is a series attempting to bring support for scans in the
IEEE 802.15.4 stack. A second series follows in order to align the
tooling with these changes, bringing support for a number of new
features such as:
* Sending (or stopping) beacons. Intervals ranging from 0 to 14 are
valid for passively sending beacons at regular intervals. An interval
of 15 would request the core to answer to received BEACON_REQ.
# iwpan dev wpan0 beacons send interval 2 # send BEACON at a fixed rate
# iwpan dev wpan0 beacons send interval 15 # answer BEACON_REQ only
# iwpan dev wpan0 beacons stop # apply to both cases
* Scanning all the channels or only a subset:
# iwpan dev wpan1 scan type passive duration 3 # will not trigger BEACON_REQ
# iwpan dev wpan1 scan type active duration 3 # will trigger BEACON_REQ
* If a beacon is received during a scan, the internal PAN list is
updated and can be dumped, flushed and configured with:
# iwpan dev wpan1 pans dump
PAN 0xffff (on wpan1)
coordinator 0x2efefdd4cdbf9330
page 0
channel 13
superframe spec. 0xcf22
LQI 0
seen 7156ms ago
# iwpan dev wpan1 pans flush
# iwpan dev wpan1 set max_pan_entries 100
# iwpan dev wpan1 set pans_expiration 3600
* It is also possible to monitor the events with:
# iwpan event
* As well as triggering a non blocking scan:
# iwpan dev wpan1 scan trigger type passive duration 3
# iwpan dev wpan1 scan done
# iwpan dev wpan1 scan abort
The PAN list gets automatically updated by dropping the expired PANs
each time the user requests access to the list.
Internally, both requests (scan/beacons) are handled periodically by
delayed workqueues when relevant.
So far the only technical point that is missing in this series is the
possibility to grab a reference over the module driving the net device
in order to prevent module unloading during a scan or when the beacons
work is ongoing.
Finally, this series is a deep reshuffle of David Girault's original
work, hence the fact that he is almost systematically credited, either
by being the only author when I created the patches based on his changes
with almost no modification, or with a Co-developped-by tag whenever the
final code base is significantly different than his first proposal while
still being greatly inspired from it.
Cheers,
Miquèl
Changes in v2:
* Create two new netlink commands to set the maximum number of PANs that
can be listed as well as their expiration time (in seconds).
* Added a patch to the series to avoid ignoring bad frames in hwsim as
requested by Alexander.
* Changed the symbol duration type to receive nanoseconds instead of
microseconds.
* Dropped most of the hwsim patches and reworked how drivers advertise
their channels in order to be capable of deriving the symbol durations
automatically.
* The scanning boolean gets turned into an atomic.
* The ca8210 driver does not support scanning, implement the driver
hooks to reflect the situation.
* Reworked a bit the content of each patch to ease the introduction of
active scans.
* Added active scan support.
David Girault (5):
net: ieee802154: Move IEEE 802.15.4 Kconfig main entry
net: mac802154: Include the softMAC stack inside the IEEE 802.15.4
menu
net: ieee802154: Move the address structure earlier
net: ieee802154: Add a kernel doc header to the ieee802154_addr
structure
net: ieee802154: Trace the registration of new PANs
Miquel Raynal (22):
net: mac802154: Split the set channel hook implementation
net: mac802154: Ensure proper channel selection at probe time
net: ieee802154: Improve the way supported channels are declared
net: ieee802154: Give more details to the core about the channel
configurations
net: mac802154: Convert the symbol duration into nanoseconds
net: mac802154: Set the symbol duration automatically
net: ieee802154: hwsim: Ensure frame checksum are valid
net: ieee802154: Drop symbol duration settings when the core does it
already
net: ieee802154: Return meaningful error codes from the netlink
helpers
net: ieee802154: Add support for internal PAN management
net: ieee802154: Define a beacon frame header
net: ieee802154: Define frame types
net: ieee802154: Add support for scanning requests
net: mac802154: Handle scan requests
net: ieee802154: Full PAN management
net: ieee802154: Add support for beacon requests
net: mac802154: Handle beacons requests
net: mac802154: Add support for active scans
net: mac802154: Add support for processing beacon requests
net: mac802154: Inform device drivers about scans
net: mac802154: Inform device drivers about beacon operations
net: ieee802154: ca8210: Refuse most of the scan operations
drivers/net/ieee802154/adf7242.c | 3 +-
drivers/net/ieee802154/at86rf230.c | 34 +-
drivers/net/ieee802154/atusb.c | 34 +-
drivers/net/ieee802154/ca8210.c | 32 +-
drivers/net/ieee802154/cc2520.c | 3 +-
drivers/net/ieee802154/fakelb.c | 43 +-
drivers/net/ieee802154/mac802154_hwsim.c | 78 +++-
drivers/net/ieee802154/mcr20a.c | 8 +-
drivers/net/ieee802154/mrf24j40.c | 3 +-
include/linux/ieee802154.h | 7 +
include/net/cfg802154.h | 167 ++++++-
include/net/ieee802154_netdev.h | 85 ++++
include/net/mac802154.h | 40 ++
include/net/nl802154.h | 99 ++++
net/Kconfig | 3 +-
net/ieee802154/Kconfig | 1 +
net/ieee802154/Makefile | 2 +-
net/ieee802154/core.c | 2 +
net/ieee802154/core.h | 31 ++
net/ieee802154/header_ops.c | 67 +++
net/ieee802154/nl-phy.c | 8 +-
net/ieee802154/nl802154.c | 548 ++++++++++++++++++++++-
net/ieee802154/nl802154.h | 4 +
net/ieee802154/pan.c | 234 ++++++++++
net/ieee802154/rdev-ops.h | 52 +++
net/ieee802154/trace.h | 86 ++++
net/mac802154/Makefile | 2 +-
net/mac802154/cfg.c | 94 +++-
net/mac802154/driver-ops.h | 58 +++
net/mac802154/ieee802154_i.h | 52 +++
net/mac802154/main.c | 113 ++++-
net/mac802154/rx.c | 34 +-
net/mac802154/scan.c | 446 ++++++++++++++++++
net/mac802154/trace.h | 49 ++
net/mac802154/tx.c | 3 +
net/mac802154/util.c | 26 ++
36 files changed, 2438 insertions(+), 113 deletions(-)
create mode 100644 net/ieee802154/pan.c
create mode 100644 net/mac802154/scan.c
--
2.27.0
As it is currently designed, the set_channel() cfg802154 hook
implemented in the softMAC is doing a couple of checks before actually
performing the channel change. However, as we enhance the support for
automatically setting the symbol duration during channel changes, it
will also be needed to ensure that the corresponding channel as properly
be selected at probe time. In order to verify this, we will need to
separate the channel change from the previous checks. These checks are
actually here to speed up the process when the user request necessitates
no change, so we can safely bypass them.
Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/cfg.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index fbeebe3bc31d..870e442bbff0 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -103,17 +103,13 @@ ieee802154_del_iface(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev)
}
static int
-ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
+ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
int ret;
ASSERT_RTNL();
- if (wpan_phy->current_page == page &&
- wpan_phy->current_channel == channel)
- return 0;
-
ret = drv_set_channel(local, page, channel);
if (!ret) {
wpan_phy->current_page = page;
@@ -123,6 +119,18 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
return ret;
}
+static int
+ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
+{
+ ASSERT_RTNL();
+
+ if (wpan_phy->current_page == page &&
+ wpan_phy->current_channel == channel)
+ return 0;
+
+ return ieee802154_change_channel(wpan_phy, page, channel);
+}
+
static int
ieee802154_set_cca_mode(struct wpan_phy *wpan_phy,
const struct wpan_phy_cca *cca)
--
2.27.0
In order to let the core derive eg. the symbol duration for a given
channel, it needs to know which protocol is being used, on which band,
and eventually more details such as the mean PRF in the case of UWB.
Create the necessary enumerations to declare all of that. Include them
in the currently-almost-empty phy_channels structure which until now
only declared the supported channels as bitfields.
The PRF is declared in a union as this clearly is a parameter that does
not apply to most of the protocols. It is very likely that other
parameters will get added in the future to further define specific
protocols and the union will likely be a good location for them.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/ca8210.c | 3 ++
drivers/net/ieee802154/mac802154_hwsim.c | 33 +++++++++++++++++++
drivers/net/ieee802154/mcr20a.c | 3 ++
include/net/cfg802154.h | 41 ++++++++++++++++++++++++
4 files changed, 80 insertions(+)
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index 1a667fceb8ba..f42a0b719a33 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -2963,7 +2963,10 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
{
/* Support channels 11-26 */
ca8210_hw->phy->supported.page[0].nchunks = 1;
+ /* 2.4 GHz O-QPSK */
ca8210_hw->phy->supported.page[0].chunk[0].channels = CA8210_VALID_CHANNELS;
+ ca8210_hw->phy->supported.page[0].chunk[0].protocol = IEEE802154_OQPSK_PHY;
+ ca8210_hw->phy->supported.page[0].chunk[0].band = IEEE802154_2400_MHZ_BAND;
ca8210_hw->phy->supported.tx_powers_size = CA8210_MAX_TX_POWERS;
ca8210_hw->phy->supported.tx_powers = ca8210_tx_powers;
ca8210_hw->phy->supported.cca_ed_levels_size = CA8210_MAX_ED_LEVELS;
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index 3a491e755022..a2827c0acabe 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -748,46 +748,79 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
hw->phy->supported.page[0].nchunks = 3;
/* 868 MHz BPSK 802.15.4-2003 */
hw->phy->supported.page[0].chunk[0].channels |= 1;
+ hw->phy->supported.page[0].chunk[0].protocol = IEEE802154_BPSK_PHY;
+ hw->phy->supported.page[0].chunk[0].band = IEEE802154_868_MHZ_BAND;
/* 915 MHz BPSK 802.15.4-2003 */
hw->phy->supported.page[0].chunk[1].channels |= 0x7fe;
+ hw->phy->supported.page[0].chunk[1].protocol = IEEE802154_BPSK_PHY;
+ hw->phy->supported.page[0].chunk[1].band = IEEE802154_915_MHZ_BAND;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
hw->phy->supported.page[0].chunk[2].channels |= 0x7FFF800;
+ hw->phy->supported.page[0].chunk[2].protocol = IEEE802154_OQPSK_PHY;
+ hw->phy->supported.page[0].chunk[2].band = IEEE802154_2400_MHZ_BAND;
hw->phy->supported.page[1].nchunks = 2;
/* 868 MHz ASK 802.15.4-2006 */
hw->phy->supported.page[1].chunk[0].channels |= 1;
+ hw->phy->supported.page[1].chunk[0].protocol = IEEE802154_ASK_PHY;
+ hw->phy->supported.page[1].chunk[0].band = IEEE802154_868_MHZ_BAND;
/* 915 MHz ASK 802.15.4-2006 */
hw->phy->supported.page[1].chunk[1].channels |= 0x7fe;
+ hw->phy->supported.page[1].chunk[1].protocol = IEEE802154_ASK_PHY;
+ hw->phy->supported.page[1].chunk[1].band = IEEE802154_915_MHZ_BAND;
hw->phy->supported.page[2].nchunks = 2;
/* 868 MHz O-QPSK 802.15.4-2006 */
hw->phy->supported.page[2].chunk[0].channels |= 1;
+ hw->phy->supported.page[2].chunk[0].protocol = IEEE802154_OQPSK_PHY;
+ hw->phy->supported.page[2].chunk[0].band = IEEE802154_868_MHZ_BAND;
/* 915 MHz O-QPSK 802.15.4-2006 */
hw->phy->supported.page[2].chunk[1].channels |= 0x7fe;
+ hw->phy->supported.page[2].chunk[1].protocol = IEEE802154_OQPSK_PHY;
+ hw->phy->supported.page[2].chunk[1].band = IEEE802154_915_MHZ_BAND;
hw->phy->supported.page[3].nchunks = 1;
/* 2.4 GHz CSS 802.15.4a-2007 */
hw->phy->supported.page[3].chunk[0].channels |= 0x3fff;
+ hw->phy->supported.page[3].chunk[0].protocol = IEEE802154_CSS_PHY;
+ hw->phy->supported.page[3].chunk[0].band = IEEE802154_2400_MHZ_BAND;
hw->phy->supported.page[4].nchunks = 3;
/* UWB Sub-gigahertz 802.15.4a-2007 */
hw->phy->supported.page[4].chunk[0].channels |= 1;
+ hw->phy->supported.page[4].chunk[0].protocol = IEEE802154_HRP_UWB_PHY;
+ hw->phy->supported.page[4].chunk[0].band = IEEE802154_250_750_MHZ_BAND;
+ hw->phy->supported.page[4].chunk[0].prf = IEEE802154_62890KHZ_MEAN_PRF;
/* UWB Low band 802.15.4a-2007 */
hw->phy->supported.page[4].chunk[1].channels |= 0x1e;
+ hw->phy->supported.page[4].chunk[1].protocol = IEEE802154_HRP_UWB_PHY;
+ hw->phy->supported.page[4].chunk[1].band = IEEE802154_3100_4800_MHZ_BAND;
+ hw->phy->supported.page[4].chunk[1].prf = IEEE802154_62890KHZ_MEAN_PRF;
/* UWB High band 802.15.4a-2007 */
hw->phy->supported.page[4].chunk[2].channels |= 0xffe0;
+ hw->phy->supported.page[4].chunk[2].protocol = IEEE802154_HRP_UWB_PHY;
+ hw->phy->supported.page[4].chunk[2].band = IEEE802154_6000_10600_MHZ_BAND;
+ hw->phy->supported.page[4].chunk[2].prf = IEEE802154_62890KHZ_MEAN_PRF;
hw->phy->supported.page[5].nchunks = 2;
/* 750 MHz O-QPSK 802.15.4c-2009 */
hw->phy->supported.page[5].chunk[0].channels |= 0xf;
+ hw->phy->supported.page[5].chunk[0].protocol = IEEE802154_OQPSK_PHY;
+ hw->phy->supported.page[5].chunk[0].band = IEEE802154_750_MHZ_BAND;
/* 750 MHz MPSK 802.15.4c-2009 */
hw->phy->supported.page[5].chunk[1].channels |= 0xf0;
+ hw->phy->supported.page[5].chunk[1].protocol = IEEE802154_MQPSK_PHY;
+ hw->phy->supported.page[5].chunk[1].band = IEEE802154_750_MHZ_BAND;
hw->phy->supported.page[6].nchunks = 2;
/* 950 MHz BPSK 802.15.4d-2009 */
hw->phy->supported.page[6].chunk[0].channels |= 0x3ff;
+ hw->phy->supported.page[6].chunk[0].protocol = IEEE802154_BPSK_PHY;
+ hw->phy->supported.page[6].chunk[0].band = IEEE802154_950_MHZ_BAND;
/* 950 MHz GFSK 802.15.4d-2009 */
hw->phy->supported.page[6].chunk[1].channels |= 0x3ffc00;
+ hw->phy->supported.page[6].chunk[1].protocol = IEEE802154_GFSK_PHY;
+ hw->phy->supported.page[6].chunk[1].band = IEEE802154_950_MHZ_BAND;
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index 5190c4d4f505..f0eb2d3b1c4e 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -1003,7 +1003,10 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
phy->cca.mode = NL802154_CCA_ENERGY;
phy->supported.page[0].nchunks = 1;
+ /* 2.4 GHz O-QPSK */
phy->supported.page[0].chunk[0].channels = MCR20A_VALID_CHANNELS;
+ phy->supported.page[0].chunk[0].protocol = IEEE802154_OQPSK_PHY;
+ phy->supported.page[0].chunk[0].band = IEEE802154_2400_MHZ_BAND;
phy->current_page = 0;
/* MCR20A default reset value */
phy->current_channel = 20;
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index ef49a23801c6..03c8008217fb 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -131,8 +131,49 @@ wpan_phy_supported_bool(bool b, enum nl802154_supported_bool_states st)
return false;
}
+enum ieee802154_phy_protocols {
+ IEEE802154_UNKNOWN_PHY,
+ IEEE802154_BPSK_PHY,
+ IEEE802154_OQPSK_PHY,
+ IEEE802154_MQPSK_PHY,
+ IEEE802154_GFSK_PHY,
+ IEEE802154_ASK_PHY,
+ IEEE802154_CSS_PHY,
+ IEEE802154_HRP_UWB_PHY,
+
+ IEEE802154_MAX_PHY,
+};
+
+enum ieee802154_phy_bands {
+ IEEE802154_UNKNOWN_BAND,
+ IEEE802154_750_MHZ_BAND,
+ IEEE802154_868_MHZ_BAND,
+ IEEE802154_915_MHZ_BAND,
+ IEEE802154_950_MHZ_BAND,
+ IEEE802154_2400_MHZ_BAND,
+ IEEE802154_250_750_MHZ_BAND,
+ IEEE802154_3100_4800_MHZ_BAND,
+ IEEE802154_6000_10600_MHZ_BAND,
+
+ IEEE802154_MAX_BAND,
+};
+
+enum ieee802154_phy_mean_prfs {
+ IEEE802154_UNKNOWN_MEAN_PRF,
+ IEEE802154_16100KHZ_MEAN_PRF,
+ IEEE802154_4030KHZ_MEAN_PRF,
+ IEEE802154_62890KHZ_MEAN_PRF,
+
+ IEEE802154_MAX_PRF,
+};
+
struct phy_channels {
u32 channels;
+ enum ieee802154_phy_protocols protocol;
+ enum ieee802154_phy_bands band;
+ union {
+ enum ieee802154_phy_mean_prfs prf;
+ };
};
struct phy_page {
--
2.27.0
Right now device drivers are encouraged to just set the ->current_page
and ->current_channel to indicate about the current state of the
hardware but this is far from ideal given the fact that we might want to
configure a few things internally, such as the symbol duration.
Call the ieee802154_change_channel() helper from the code section
registering the hardware to ensure proper channel selection and
configuration both on the device side and the core side.
This change somehow "fixes" the hwsim driver which advertises using page
0 channel 13, but does not actually update its own internal pib
structure to reflect that configuration.
Signed-off-by: Miquel Raynal <[email protected]>
---
net/mac802154/cfg.c | 3 +--
net/mac802154/ieee802154_i.h | 1 +
net/mac802154/main.c | 8 ++++++++
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index 870e442bbff0..6969f1330ccd 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -102,8 +102,7 @@ ieee802154_del_iface(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev)
return 0;
}
-static int
-ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
+int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
int ret;
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 702560acc8ce..8a7f4c83c5b6 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -127,6 +127,7 @@ ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev);
netdev_tx_t
ieee802154_subif_start_xmit(struct sk_buff *skb, struct net_device *dev);
enum hrtimer_restart ieee802154_xmit_ifs_timer(struct hrtimer *timer);
+int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel);
/* MIB callbacks */
void mac802154_dev_set_page_channel(struct net_device *dev, u8 page, u8 chan);
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 520cedc594e1..12ab1545e871 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -157,6 +157,14 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)
ieee802154_setup_wpan_phy_pib(local->phy);
+ /* Ensure proper channel selection */
+ rtnl_lock();
+ rc = ieee802154_change_channel(local->phy, local->phy->current_page,
+ local->phy->current_channel);
+ rtnl_unlock();
+ if (rc)
+ goto out_wq;
+
if (!(hw->flags & IEEE802154_HW_CSMA_PARAMS)) {
local->phy->supported.min_csma_backoffs = 4;
local->phy->supported.max_csma_backoffs = 4;
--
2.27.0
Now that we have access to all the basic information to know which
symbol duration should be applied, let's set the symbol duration
automatically. The two locations that must call for the symbol duration
to be set are:
- when manually requesting a channel change though the netlink interface
- at PHY creation, ieee802154_alloc_hw() already calls
ieee802154_change_channel() which will now update the symbol duration
accordingly.
If an information is missing, the symbol duration is not touched, a
debug message is eventually printed. This keeps the compatibility with
the unconverted drivers for which it was too complicated for me to find
their precise information. If they initially provided a symbol duration,
it would be kept. If they don't, the symbol duration value is left
untouched.
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 2 +
net/mac802154/cfg.c | 1 +
net/mac802154/main.c | 93 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 96 insertions(+)
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 286709a9dd0b..52eefc4b5b4d 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -455,4 +455,6 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
return dev_name(&phy->dev);
}
+void ieee802154_set_symbol_duration(struct wpan_phy *phy);
+
#endif /* __NET_CFG802154_H */
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index 6969f1330ccd..ba57da07c08e 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -113,6 +113,7 @@ int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
if (!ret) {
wpan_phy->current_page = page;
wpan_phy->current_channel = channel;
+ ieee802154_set_symbol_duration(wpan_phy);
}
return ret;
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 77a4943f345f..88826c5aa4ba 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -113,6 +113,99 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
}
EXPORT_SYMBOL(ieee802154_alloc_hw);
+void ieee802154_set_symbol_duration(struct wpan_phy *phy)
+{
+ struct phy_page *page = &phy->supported.page[phy->current_page];
+ struct phy_channels *chan;
+ unsigned int chunk;
+ u32 duration = 0;
+
+ for (chunk = 0; chunk < page->nchunks; chunk++) {
+ if (page->chunk[chunk].channels & phy->current_channel)
+ break;
+ }
+
+ if (chunk == page->nchunks)
+ goto set_duration;
+
+ chan = &page->chunk[chunk];
+ switch (chan->protocol) {
+ case IEEE802154_BPSK_PHY:
+ switch (chan->band) {
+ case IEEE802154_868_MHZ_BAND:
+ /* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */
+ duration = 50 * 1000;
+ break;
+ case IEEE802154_915_MHZ_BAND:
+ /* 915 MHz BPSK 802.15.4-2003: 40 ksym/s */
+ duration = 25 * 1000;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IEEE802154_OQPSK_PHY:
+ switch (chan->band) {
+ case IEEE802154_868_MHZ_BAND:
+ /* 868 MHz O-QPSK 802.15.4-2006: 25 ksym/s */
+ duration = 40 * 1000;
+ break;
+ case IEEE802154_915_MHZ_BAND:
+ case IEEE802154_2400_MHZ_BAND:
+ /* 915/2400 MHz O-QPSK 802.15.4-2006: 62.5 ksym/s */
+ duration = 16 * 1000;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IEEE802154_CSS_PHY:
+ switch (chan->band) {
+ case IEEE802154_2400_MHZ_BAND:
+ /* 2.4 GHz CSS 802.15.4a-2007: 1/6 Msym/s */
+ duration = 6 * 1000;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IEEE802154_HRP_UWB_PHY:
+ switch (chan->band) {
+ case IEEE802154_250_750_MHZ_BAND:
+ case IEEE802154_3100_4800_MHZ_BAND:
+ case IEEE802154_6000_10600_MHZ_BAND:
+ break;
+ default:
+ goto set_duration;
+ }
+
+ /* UWB 802.15.4a-2007: 993.6 or 1017.6 or 3974.4 ns */
+ switch (chan->prf) {
+ case IEEE802154_16100KHZ_MEAN_PRF:
+ duration = 994;
+ break;
+ case IEEE802154_4030KHZ_MEAN_PRF:
+ duration = 3974;
+ break;
+ case IEEE802154_62890KHZ_MEAN_PRF:
+ duration = 1018;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+set_duration:
+ if (!duration)
+ pr_debug("Unknown PHY symbol duration, the driver should be fixed\n");
+ else
+ phy->symbol_duration = duration;
+}
+EXPORT_SYMBOL(ieee802154_set_symbol_duration);
+
void ieee802154_free_hw(struct ieee802154_hw *hw)
{
struct ieee802154_local *local = hw_to_local(hw);
--
2.27.0
The idea here is to create a structure per set of channels so that we
can define much more than basic bitfields for these.
The structure is currently almost empty on purpose because this change
is supposed to be a mechanical update without additional information but
more details will be added in the following commits.
For each page, the core now has access to how many "chunks" of channels
are defined. Overall up to only 3 chunks have been defined so let's
hardcode this value to simplify a lot the handling. Then, for each
chunk, we define an independent bitfield of channels. As there are
several users of these bitfields, we also create the
cfg802154_get_supported_chans() helper to reconstruct the bitfield as it
was before when the only information that matters is identifying the
supported/unsupported channels.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/adf7242.c | 3 +-
drivers/net/ieee802154/at86rf230.c | 12 ++++---
drivers/net/ieee802154/atusb.c | 12 ++++---
drivers/net/ieee802154/ca8210.c | 3 +-
drivers/net/ieee802154/cc2520.c | 3 +-
drivers/net/ieee802154/fakelb.c | 43 +++++++++++++++---------
drivers/net/ieee802154/mac802154_hwsim.c | 43 +++++++++++++++---------
drivers/net/ieee802154/mcr20a.c | 3 +-
drivers/net/ieee802154/mrf24j40.c | 3 +-
include/net/cfg802154.h | 13 +++++--
net/ieee802154/core.h | 2 ++
net/ieee802154/nl-phy.c | 8 +++--
net/ieee802154/nl802154.c | 30 +++++++++++++----
13 files changed, 125 insertions(+), 53 deletions(-)
diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c
index 7db9cbd0f5de..40c77a643b78 100644
--- a/drivers/net/ieee802154/adf7242.c
+++ b/drivers/net/ieee802154/adf7242.c
@@ -1211,7 +1211,8 @@ static int adf7242_probe(struct spi_device *spi)
hw->extra_tx_headroom = 0;
/* We support only 2.4 Ghz */
- hw->phy->supported.channels[0] = 0x7FFF800;
+ hw->phy->supported.page[0].nchunks = 1;
+ hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
hw->flags = IEEE802154_HW_OMIT_CKSUM |
IEEE802154_HW_CSMA_PARAMS |
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index 7d67f41387f5..cdf5d2a4f763 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -1558,7 +1558,8 @@ at86rf230_detect_device(struct at86rf230_local *lp)
case 3:
chip = "at86rf231";
lp->data = &at86rf231_data;
- lp->hw->phy->supported.channels[0] = 0x7FFF800;
+ lp->hw->phy->supported.page[0].nchunks = 1;
+ lp->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
lp->hw->phy->current_channel = 11;
lp->hw->phy->symbol_duration = 16;
lp->hw->phy->supported.tx_powers = at86rf231_powers;
@@ -1570,8 +1571,10 @@ at86rf230_detect_device(struct at86rf230_local *lp)
chip = "at86rf212";
lp->data = &at86rf212_data;
lp->hw->flags |= IEEE802154_HW_LBT;
- lp->hw->phy->supported.channels[0] = 0x00007FF;
- lp->hw->phy->supported.channels[2] = 0x00007FF;
+ lp->hw->phy->supported.page[0].nchunks = 1;
+ lp->hw->phy->supported.page[0].chunk[0].channels = 0x00007FF;
+ lp->hw->phy->supported.page[2].nchunks = 1;
+ lp->hw->phy->supported.page[2].chunk[0].channels = 0x00007FF;
lp->hw->phy->current_channel = 5;
lp->hw->phy->symbol_duration = 25;
lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
@@ -1583,7 +1586,8 @@ at86rf230_detect_device(struct at86rf230_local *lp)
case 11:
chip = "at86rf233";
lp->data = &at86rf233_data;
- lp->hw->phy->supported.channels[0] = 0x7FFF800;
+ lp->hw->phy->supported.page[0].nchunks = 1;
+ lp->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
lp->hw->phy->current_channel = 13;
lp->hw->phy->symbol_duration = 16;
lp->hw->phy->supported.tx_powers = at86rf233_powers;
diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
index 23ee0b14cbfa..38ebfacf2698 100644
--- a/drivers/net/ieee802154/atusb.c
+++ b/drivers/net/ieee802154/atusb.c
@@ -914,7 +914,8 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
switch (part_num) {
case 2:
chip = "AT86RF230";
- atusb->hw->phy->supported.channels[0] = 0x7FFF800;
+ atusb->hw->phy->supported.page[0].nchunks = 1;
+ atusb->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
atusb->hw->phy->current_channel = 11; /* reset default */
atusb->hw->phy->symbol_duration = 16;
atusb->hw->phy->supported.tx_powers = atusb_powers;
@@ -924,7 +925,8 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
break;
case 3:
chip = "AT86RF231";
- atusb->hw->phy->supported.channels[0] = 0x7FFF800;
+ atusb->hw->phy->supported.page[0].nchunks = 1;
+ atusb->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
atusb->hw->phy->current_channel = 11; /* reset default */
atusb->hw->phy->symbol_duration = 16;
atusb->hw->phy->supported.tx_powers = atusb_powers;
@@ -935,8 +937,10 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
case 7:
chip = "AT86RF212";
atusb->hw->flags |= IEEE802154_HW_LBT;
- atusb->hw->phy->supported.channels[0] = 0x00007FF;
- atusb->hw->phy->supported.channels[2] = 0x00007FF;
+ atusb->hw->phy->supported.page[0].nchunks = 1;
+ atusb->hw->phy->supported.page[0].chunk[0].channels = 0x00007FF;
+ atusb->hw->phy->supported.page[2].nchunks = 1;
+ atusb->hw->phy->supported.page[2].chunk[0].channels = 0x00007FF;
atusb->hw->phy->current_channel = 5;
atusb->hw->phy->symbol_duration = 25;
atusb->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index ece6ff6049f6..1a667fceb8ba 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -2962,7 +2962,8 @@ static const s32 ca8210_ed_levels[CA8210_MAX_ED_LEVELS] = {
static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
{
/* Support channels 11-26 */
- ca8210_hw->phy->supported.channels[0] = CA8210_VALID_CHANNELS;
+ ca8210_hw->phy->supported.page[0].nchunks = 1;
+ ca8210_hw->phy->supported.page[0].chunk[0].channels = CA8210_VALID_CHANNELS;
ca8210_hw->phy->supported.tx_powers_size = CA8210_MAX_TX_POWERS;
ca8210_hw->phy->supported.tx_powers = ca8210_tx_powers;
ca8210_hw->phy->supported.cca_ed_levels_size = CA8210_MAX_ED_LEVELS;
diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index 89c046b204e0..587f050ef4e8 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -836,7 +836,8 @@ static int cc2520_register(struct cc2520_private *priv)
ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);
/* We do support only 2.4 Ghz */
- priv->hw->phy->supported.channels[0] = 0x7FFF800;
+ priv->hw->phy->supported.page[0].nchunks = 1;
+ priv->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
priv->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
IEEE802154_HW_PROMISCUOUS;
diff --git a/drivers/net/ieee802154/fakelb.c b/drivers/net/ieee802154/fakelb.c
index 523d13ee02bf..bc44d1f7551c 100644
--- a/drivers/net/ieee802154/fakelb.c
+++ b/drivers/net/ieee802154/fakelb.c
@@ -137,36 +137,49 @@ static int fakelb_add_one(struct device *dev)
phy = hw->priv;
phy->hw = hw;
+ hw->phy->supported.page[0].nchunks = 3;
/* 868 MHz BPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 1;
+ hw->phy->supported.page[0].chunk[0].channels |= 1;
/* 915 MHz BPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 0x7fe;
+ hw->phy->supported.page[0].chunk[1].channels |= 0x7fe;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 0x7FFF800;
+ hw->phy->supported.page[0].chunk[2].channels |= 0x7FFF800;
+
+ hw->phy->supported.page[1].nchunks = 2;
/* 868 MHz ASK 802.15.4-2006 */
- hw->phy->supported.channels[1] |= 1;
+ hw->phy->supported.page[1].chunk[0].channels |= 1;
/* 915 MHz ASK 802.15.4-2006 */
- hw->phy->supported.channels[1] |= 0x7fe;
+ hw->phy->supported.page[1].chunk[1].channels |= 0x7fe;
+
+ hw->phy->supported.page[2].nchunks = 2;
/* 868 MHz O-QPSK 802.15.4-2006 */
- hw->phy->supported.channels[2] |= 1;
+ hw->phy->supported.page[2].chunk[0].channels |= 1;
/* 915 MHz O-QPSK 802.15.4-2006 */
- hw->phy->supported.channels[2] |= 0x7fe;
+ hw->phy->supported.page[2].chunk[1].channels |= 0x7fe;
+
+ hw->phy->supported.page[3].nchunks = 1;
/* 2.4 GHz CSS 802.15.4a-2007 */
- hw->phy->supported.channels[3] |= 0x3fff;
+ hw->phy->supported.page[3].chunk[0].channels |= 0x3fff;
+
+ hw->phy->supported.page[4].nchunks = 3;
/* UWB Sub-gigahertz 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 1;
+ hw->phy->supported.page[4].chunk[0].channels |= 1;
/* UWB Low band 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 0x1e;
+ hw->phy->supported.page[4].chunk[1].channels |= 0x1e;
/* UWB High band 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 0xffe0;
+ hw->phy->supported.page[4].chunk[2].channels |= 0xffe0;
+
+ hw->phy->supported.page[5].nchunks = 2;
/* 750 MHz O-QPSK 802.15.4c-2009 */
- hw->phy->supported.channels[5] |= 0xf;
+ hw->phy->supported.page[5].chunk[0].channels |= 0xf;
/* 750 MHz MPSK 802.15.4c-2009 */
- hw->phy->supported.channels[5] |= 0xf0;
+ hw->phy->supported.page[5].chunk[1].channels |= 0xf0;
+
+ hw->phy->supported.page[6].nchunks = 2;
/* 950 MHz BPSK 802.15.4d-2009 */
- hw->phy->supported.channels[6] |= 0x3ff;
+ hw->phy->supported.page[6].chunk[0].channels |= 0x3ff;
/* 950 MHz GFSK 802.15.4d-2009 */
- hw->phy->supported.channels[6] |= 0x3ffc00;
+ hw->phy->supported.page[6].chunk[1].channels |= 0x3ffc00;
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
/* fake phy channel 13 as default */
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index 8caa61ec718f..3a491e755022 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -745,36 +745,49 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
phy = hw->priv;
phy->hw = hw;
+ hw->phy->supported.page[0].nchunks = 3;
/* 868 MHz BPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 1;
+ hw->phy->supported.page[0].chunk[0].channels |= 1;
/* 915 MHz BPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 0x7fe;
+ hw->phy->supported.page[0].chunk[1].channels |= 0x7fe;
/* 2.4 GHz O-QPSK 802.15.4-2003 */
- hw->phy->supported.channels[0] |= 0x7FFF800;
+ hw->phy->supported.page[0].chunk[2].channels |= 0x7FFF800;
+
+ hw->phy->supported.page[1].nchunks = 2;
/* 868 MHz ASK 802.15.4-2006 */
- hw->phy->supported.channels[1] |= 1;
+ hw->phy->supported.page[1].chunk[0].channels |= 1;
/* 915 MHz ASK 802.15.4-2006 */
- hw->phy->supported.channels[1] |= 0x7fe;
+ hw->phy->supported.page[1].chunk[1].channels |= 0x7fe;
+
+ hw->phy->supported.page[2].nchunks = 2;
/* 868 MHz O-QPSK 802.15.4-2006 */
- hw->phy->supported.channels[2] |= 1;
+ hw->phy->supported.page[2].chunk[0].channels |= 1;
/* 915 MHz O-QPSK 802.15.4-2006 */
- hw->phy->supported.channels[2] |= 0x7fe;
+ hw->phy->supported.page[2].chunk[1].channels |= 0x7fe;
+
+ hw->phy->supported.page[3].nchunks = 1;
/* 2.4 GHz CSS 802.15.4a-2007 */
- hw->phy->supported.channels[3] |= 0x3fff;
+ hw->phy->supported.page[3].chunk[0].channels |= 0x3fff;
+
+ hw->phy->supported.page[4].nchunks = 3;
/* UWB Sub-gigahertz 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 1;
+ hw->phy->supported.page[4].chunk[0].channels |= 1;
/* UWB Low band 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 0x1e;
+ hw->phy->supported.page[4].chunk[1].channels |= 0x1e;
/* UWB High band 802.15.4a-2007 */
- hw->phy->supported.channels[4] |= 0xffe0;
+ hw->phy->supported.page[4].chunk[2].channels |= 0xffe0;
+
+ hw->phy->supported.page[5].nchunks = 2;
/* 750 MHz O-QPSK 802.15.4c-2009 */
- hw->phy->supported.channels[5] |= 0xf;
+ hw->phy->supported.page[5].chunk[0].channels |= 0xf;
/* 750 MHz MPSK 802.15.4c-2009 */
- hw->phy->supported.channels[5] |= 0xf0;
+ hw->phy->supported.page[5].chunk[1].channels |= 0xf0;
+
+ hw->phy->supported.page[6].nchunks = 2;
/* 950 MHz BPSK 802.15.4d-2009 */
- hw->phy->supported.channels[6] |= 0x3ff;
+ hw->phy->supported.page[6].chunk[0].channels |= 0x3ff;
/* 950 MHz GFSK 802.15.4d-2009 */
- hw->phy->supported.channels[6] |= 0x3ffc00;
+ hw->phy->supported.page[6].chunk[1].channels |= 0x3ffc00;
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);
diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index 8dc04e2590b1..5190c4d4f505 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -1002,7 +1002,8 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
phy->cca.mode = NL802154_CCA_ENERGY;
- phy->supported.channels[0] = MCR20A_VALID_CHANNELS;
+ phy->supported.page[0].nchunks = 1;
+ phy->supported.page[0].chunk[0].channels = MCR20A_VALID_CHANNELS;
phy->current_page = 0;
/* MCR20A default reset value */
phy->current_channel = 20;
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index ff83e00b77af..5a38f3077771 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -1287,7 +1287,8 @@ static int mrf24j40_probe(struct spi_device *spi)
spi_set_drvdata(spi, devrec);
devrec->hw = hw;
devrec->hw->parent = &spi->dev;
- devrec->hw->phy->supported.channels[0] = CHANNEL_MASK;
+ devrec->hw->phy->supported.page[0].nchunks = 1;
+ devrec->hw->phy->supported.page[0].chunk[0].channels = CHANNEL_MASK;
devrec->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
IEEE802154_HW_CSMA_PARAMS |
IEEE802154_HW_PROMISCUOUS;
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 6ed07844eb24..ef49a23801c6 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -131,9 +131,18 @@ wpan_phy_supported_bool(bool b, enum nl802154_supported_bool_states st)
return false;
}
+struct phy_channels {
+ u32 channels;
+};
+
+struct phy_page {
+ unsigned int nchunks;
+ struct phy_channels chunk[3];
+};
+
struct wpan_phy_supported {
- u32 channels[IEEE802154_MAX_PAGE + 1],
- cca_modes, cca_opts, iftypes;
+ struct phy_page page[IEEE802154_MAX_PAGE + 1];
+ u32 cca_modes, cca_opts, iftypes;
enum nl802154_supported_bool_states lbt;
u8 min_minbe, max_minbe, min_maxbe, max_maxbe,
min_csma_backoffs, max_csma_backoffs;
diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h
index 1c19f575d574..a0cf6feffc6a 100644
--- a/net/ieee802154/core.h
+++ b/net/ieee802154/core.h
@@ -47,4 +47,6 @@ struct cfg802154_registered_device *
cfg802154_rdev_by_wpan_phy_idx(int wpan_phy_idx);
struct wpan_phy *wpan_phy_idx_to_wpan_phy(int wpan_phy_idx);
+u32 cfg802154_get_supported_chans(struct wpan_phy *phy, unsigned int page);
+
#endif /* __IEEE802154_CORE_H */
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index dd5a45f8a78a..59e45e554834 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -31,6 +31,7 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
void *hdr;
int i, pages = 0;
uint32_t *buf = kcalloc(32, sizeof(uint32_t), GFP_KERNEL);
+ u32 chans;
pr_debug("%s\n", __func__);
@@ -48,8 +49,11 @@ static int ieee802154_nl_fill_phy(struct sk_buff *msg, u32 portid,
nla_put_u8(msg, IEEE802154_ATTR_CHANNEL, phy->current_channel))
goto nla_put_failure;
for (i = 0; i < 32; i++) {
- if (phy->supported.channels[i])
- buf[pages++] = phy->supported.channels[i] | (i << 27);
+ chans = cfg802154_get_supported_chans(phy, i);
+ if (!chans)
+ continue;
+
+ buf[pages++] = chans | (i << 27);
}
if (pages &&
nla_put(msg, IEEE802154_ATTR_CHANNEL_PAGE_LIST,
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 277124f206e0..45e2c9b0505a 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -320,6 +320,21 @@ nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
return 0;
}
+u32 cfg802154_get_supported_chans(struct wpan_phy *phy, unsigned int page)
+{
+ struct phy_page *ppage;
+ unsigned int chunk;
+ u32 supported = 0;
+
+ ppage = &phy->supported.page[page];
+
+ for (chunk = 0; chunk <= ppage->nchunks; chunk++)
+ supported |= ppage->chunk[chunk].channels;
+
+ return supported;
+}
+EXPORT_SYMBOL(cfg802154_get_supported_chans);
+
static int
nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
struct sk_buff *msg)
@@ -333,7 +348,7 @@ nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
- rdev->wpan_phy.supported.channels[page]))
+ cfg802154_get_supported_chans(&rdev->wpan_phy, page)))
return -ENOBUFS;
}
nla_nest_end(msg, nl_page);
@@ -347,6 +362,7 @@ nl802154_put_capabilities(struct sk_buff *msg,
{
const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
struct nlattr *nl_caps, *nl_channels;
+ u32 chans;
int i;
nl_caps = nla_nest_start_noflag(msg, NL802154_ATTR_WPAN_PHY_CAPS);
@@ -358,10 +374,12 @@ nl802154_put_capabilities(struct sk_buff *msg,
return -ENOBUFS;
for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
- if (caps->channels[i]) {
- if (nl802154_put_flags(msg, i, caps->channels[i]))
- return -ENOBUFS;
- }
+ chans = cfg802154_get_supported_chans(&rdev->wpan_phy, i);
+ if (!chans)
+ continue;
+
+ if (nl802154_put_flags(msg, i, chans))
+ return -ENOBUFS;
}
nla_nest_end(msg, nl_channels);
@@ -965,7 +983,7 @@ static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
/* check 802.15.4 constraints */
if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
- !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
+ !(cfg802154_get_supported_chans(&rdev->wpan_phy, page) & BIT(channel)))
return -EINVAL;
return rdev_set_channel(rdev, page, channel);
--
2.27.0
There is no point in accepting frames with a wrong or missing checksum,
at least not outside of a promiscuous setting. Set the right flag by
default in the hwsim driver to ensure checksums are not ignored.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/mac802154_hwsim.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
index a2827c0acabe..8f87f2b8129d 100644
--- a/drivers/net/ieee802154/mac802154_hwsim.c
+++ b/drivers/net/ieee802154/mac802154_hwsim.c
@@ -836,7 +836,7 @@ static int hwsim_add_one(struct genl_info *info, struct device *dev,
phy->idx = idx;
INIT_LIST_HEAD(&phy->edges);
- hw->flags = IEEE802154_HW_PROMISCUOUS;
+ hw->flags = IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_RX_DROP_BAD_CKSUM;
hw->parent = dev;
err = ieee802154_register_hw(hw);
--
2.27.0
Tdsym is often given in the spec as pretty small numbers in microseconds
and hence was reflected in the code as symbol_duration and was stored as
a u8. Actually, for UWB PHYs, the symbol duration is given in
nanoseconds and are as precise as picoseconds. In order to handle better
these PHYs, change the type of symbol_duration to u32 and store this
value in nanoseconds.
All the users of this variable are updated in a mechanical change.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/at86rf230.c | 22 +++++++++++-----------
drivers/net/ieee802154/atusb.c | 22 +++++++++++-----------
drivers/net/ieee802154/ca8210.c | 2 +-
drivers/net/ieee802154/mcr20a.c | 4 ++--
include/net/cfg802154.h | 4 ++--
net/mac802154/main.c | 8 ++++----
6 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index cdf5d2a4f763..47dafefedf79 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -1066,24 +1066,24 @@ at86rf212_set_channel(struct at86rf230_local *lp, u8 page, u8 channel)
if (channel == 0) {
if (page == 0) {
/* SUB:0 and BPSK:0 -> BPSK-20 */
- lp->hw->phy->symbol_duration = 50;
+ lp->hw->phy->symbol_duration = 50 * 1000;
} else {
/* SUB:1 and BPSK:0 -> BPSK-40 */
- lp->hw->phy->symbol_duration = 25;
+ lp->hw->phy->symbol_duration = 25 * 1000;
}
} else {
if (page == 0)
/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
- lp->hw->phy->symbol_duration = 40;
+ lp->hw->phy->symbol_duration = 40 * 1000;
else
/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
- lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->symbol_duration = 16 * 1000;
}
- lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD *
- lp->hw->phy->symbol_duration;
- lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD *
- lp->hw->phy->symbol_duration;
+ lp->hw->phy->lifs_period =
+ (IEEE802154_LIFS_PERIOD * lp->hw->phy->symbol_duration) / 1000;
+ lp->hw->phy->sifs_period =
+ (IEEE802154_SIFS_PERIOD * lp->hw->phy->symbol_duration) / 1000;
return at86rf230_write_subreg(lp, SR_CHANNEL, channel);
}
@@ -1561,7 +1561,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
lp->hw->phy->supported.page[0].nchunks = 1;
lp->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
lp->hw->phy->current_channel = 11;
- lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->symbol_duration = 16 * 1000;
lp->hw->phy->supported.tx_powers = at86rf231_powers;
lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf231_powers);
lp->hw->phy->supported.cca_ed_levels = at86rf231_ed_levels;
@@ -1576,7 +1576,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
lp->hw->phy->supported.page[2].nchunks = 1;
lp->hw->phy->supported.page[2].chunk[0].channels = 0x00007FF;
lp->hw->phy->current_channel = 5;
- lp->hw->phy->symbol_duration = 25;
+ lp->hw->phy->symbol_duration = 25 * 1000;
lp->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
lp->hw->phy->supported.tx_powers = at86rf212_powers;
lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
@@ -1589,7 +1589,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
lp->hw->phy->supported.page[0].nchunks = 1;
lp->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
lp->hw->phy->current_channel = 13;
- lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->symbol_duration = 16 * 1000;
lp->hw->phy->supported.tx_powers = at86rf233_powers;
lp->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf233_powers);
lp->hw->phy->supported.cca_ed_levels = at86rf233_ed_levels;
diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c
index 38ebfacf2698..099113bd4a26 100644
--- a/drivers/net/ieee802154/atusb.c
+++ b/drivers/net/ieee802154/atusb.c
@@ -678,24 +678,24 @@ static int hulusb_set_channel(struct ieee802154_hw *hw, u8 page, u8 channel)
if (channel == 0) {
if (page == 0) {
/* SUB:0 and BPSK:0 -> BPSK-20 */
- lp->hw->phy->symbol_duration = 50;
+ lp->hw->phy->symbol_duration = 50 * 1000;
} else {
/* SUB:1 and BPSK:0 -> BPSK-40 */
- lp->hw->phy->symbol_duration = 25;
+ lp->hw->phy->symbol_duration = 25 * 1000;
}
} else {
if (page == 0)
/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
- lp->hw->phy->symbol_duration = 40;
+ lp->hw->phy->symbol_duration = 40 * 1000;
else
/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
- lp->hw->phy->symbol_duration = 16;
+ lp->hw->phy->symbol_duration = 16 * 1000;
}
- lp->hw->phy->lifs_period = IEEE802154_LIFS_PERIOD *
- lp->hw->phy->symbol_duration;
- lp->hw->phy->sifs_period = IEEE802154_SIFS_PERIOD *
- lp->hw->phy->symbol_duration;
+ lp->hw->phy->lifs_period =
+ (IEEE802154_LIFS_PERIOD * lp->hw->phy->symbol_duration) / 1000;
+ lp->hw->phy->sifs_period =
+ (IEEE802154_SIFS_PERIOD * lp->hw->phy->symbol_duration) / 1000;
return atusb_write_subreg(lp, SR_CHANNEL, channel);
}
@@ -917,7 +917,7 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
atusb->hw->phy->supported.page[0].nchunks = 1;
atusb->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
atusb->hw->phy->current_channel = 11; /* reset default */
- atusb->hw->phy->symbol_duration = 16;
+ atusb->hw->phy->symbol_duration = 16 * 1000;
atusb->hw->phy->supported.tx_powers = atusb_powers;
atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
hw->phy->supported.cca_ed_levels = atusb_ed_levels;
@@ -928,7 +928,7 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
atusb->hw->phy->supported.page[0].nchunks = 1;
atusb->hw->phy->supported.page[0].chunk[0].channels = 0x7FFF800;
atusb->hw->phy->current_channel = 11; /* reset default */
- atusb->hw->phy->symbol_duration = 16;
+ atusb->hw->phy->symbol_duration = 16 * 1000;
atusb->hw->phy->supported.tx_powers = atusb_powers;
atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(atusb_powers);
hw->phy->supported.cca_ed_levels = atusb_ed_levels;
@@ -942,7 +942,7 @@ static int atusb_get_and_conf_chip(struct atusb *atusb)
atusb->hw->phy->supported.page[2].nchunks = 1;
atusb->hw->phy->supported.page[2].chunk[0].channels = 0x00007FF;
atusb->hw->phy->current_channel = 5;
- atusb->hw->phy->symbol_duration = 25;
+ atusb->hw->phy->symbol_duration = 25 * 1000;
atusb->hw->phy->supported.lbt = NL802154_SUPPORTED_BOOL_BOTH;
atusb->hw->phy->supported.tx_powers = at86rf212_powers;
atusb->hw->phy->supported.tx_powers_size = ARRAY_SIZE(at86rf212_powers);
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index f42a0b719a33..82b2a173bdbd 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -2977,7 +2977,7 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
ca8210_hw->phy->cca_ed_level = -9800;
- ca8210_hw->phy->symbol_duration = 16;
+ ca8210_hw->phy->symbol_duration = 16 * 1000;
ca8210_hw->phy->lifs_period = 40;
ca8210_hw->phy->sifs_period = 12;
ca8210_hw->flags =
diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index f0eb2d3b1c4e..8aa87e9bf92e 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -975,7 +975,7 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
dev_dbg(printdev(lp), "%s\n", __func__);
- phy->symbol_duration = 16;
+ phy->symbol_duration = 16 * 1000;
phy->lifs_period = 40;
phy->sifs_period = 12;
@@ -1010,7 +1010,7 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
phy->current_page = 0;
/* MCR20A default reset value */
phy->current_channel = 20;
- phy->symbol_duration = 16;
+ phy->symbol_duration = 16 * 1000;
phy->supported.tx_powers = mcr20a_powers;
phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
phy->cca_ed_level = phy->supported.cca_ed_levels[75];
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 03c8008217fb..286709a9dd0b 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -253,8 +253,8 @@ struct wpan_phy {
/* PHY depended MAC PIB values */
- /* 802.15.4 acronym: Tdsym in usec */
- u8 symbol_duration;
+ /* 802.15.4 acronym: Tdsym in nsec */
+ u32 symbol_duration;
/* lifs and sifs periods timing */
u16 lifs_period;
u16 sifs_period;
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 12ab1545e871..77a4943f345f 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -131,10 +131,10 @@ static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy)
* Should be done when all drivers sets this value.
*/
- wpan_phy->lifs_period = IEEE802154_LIFS_PERIOD *
- wpan_phy->symbol_duration;
- wpan_phy->sifs_period = IEEE802154_SIFS_PERIOD *
- wpan_phy->symbol_duration;
+ wpan_phy->lifs_period =
+ (IEEE802154_LIFS_PERIOD * wpan_phy->symbol_duration) / 1000;
+ wpan_phy->sifs_period =
+ (IEEE802154_SIFS_PERIOD * wpan_phy->symbol_duration) / 1000;
}
int ieee802154_register_hw(struct ieee802154_hw *hw)
--
2.27.0
The core now knows how to set the symbol duration in a few cases, when
drivers correctly advertise the protocols used on each channel. For
these drivers, there is no more need to bother with symbol duration, so
just drop the duplicated code.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/ca8210.c | 1 -
drivers/net/ieee802154/mcr20a.c | 2 --
2 files changed, 3 deletions(-)
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index 82b2a173bdbd..d3a9e4fe05f4 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
ca8210_hw->phy->cca_ed_level = -9800;
- ca8210_hw->phy->symbol_duration = 16 * 1000;
ca8210_hw->phy->lifs_period = 40;
ca8210_hw->phy->sifs_period = 12;
ca8210_hw->flags =
diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index 8aa87e9bf92e..da2ab19cb5ee 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
dev_dbg(printdev(lp), "%s\n", __func__);
- phy->symbol_duration = 16 * 1000;
phy->lifs_period = 40;
phy->sifs_period = 12;
@@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
phy->current_page = 0;
/* MCR20A default reset value */
phy->current_channel = 20;
- phy->symbol_duration = 16 * 1000;
phy->supported.tx_powers = mcr20a_powers;
phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
phy->cca_ed_level = phy->supported.cca_ed_levels[75];
--
2.27.0
From: David Girault <[email protected]>
Move the address structure earlier in the cfg802154.h header in order to
use it in subsequent additions. There is no functional change here.
Signed-off-by: David Girault <[email protected]>
[[email protected]: Isolate this change from a bigger commit]
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 52eefc4b5b4d..f8ea3d519865 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -29,6 +29,15 @@ struct ieee802154_llsec_key_id;
struct ieee802154_llsec_key;
#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
+struct ieee802154_addr {
+ u8 mode;
+ __le16 pan_id;
+ union {
+ __le16 short_addr;
+ __le64 extended_addr;
+ };
+};
+
struct cfg802154_ops {
struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
const char *name,
@@ -277,15 +286,6 @@ static inline void wpan_phy_net_set(struct wpan_phy *wpan_phy, struct net *net)
write_pnet(&wpan_phy->_net, net);
}
-struct ieee802154_addr {
- u8 mode;
- __le16 pan_id;
- union {
- __le16 short_addr;
- __le64 extended_addr;
- };
-};
-
struct ieee802154_llsec_key_id {
u8 mode;
u8 id;
--
2.27.0
From: David Girault <[email protected]>
It makes certainly more sense to have all the low-range wireless
protocols such as Bluetooth, IEEE 802.11 (WiFi) and IEEE 802.15.4
together, so let's move the main IEEE 802.15.4 stack Kconfig entry at a
better location.
Signed-off-by: David Girault <[email protected]>
[[email protected]: Isolate this change from a bigger commit and
rewrite the commit message.]
Signed-off-by: Miquel Raynal <[email protected]>
---
net/Kconfig | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/Kconfig b/net/Kconfig
index 8a1f9d0287de..0da89d09ffa6 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -228,7 +228,6 @@ source "net/x25/Kconfig"
source "net/lapb/Kconfig"
source "net/phonet/Kconfig"
source "net/6lowpan/Kconfig"
-source "net/ieee802154/Kconfig"
source "net/mac802154/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
@@ -380,6 +379,7 @@ source "net/mac80211/Kconfig"
endif # WIRELESS
+source "net/ieee802154/Kconfig"
source "net/rfkill/Kconfig"
source "net/9p/Kconfig"
source "net/caif/Kconfig"
--
2.27.0
From: David Girault <[email protected]>
The softMAC stack has no meaning outside of the IEEE 802.15.4 stack and
cannot be used without it.
Signed-off-by: David Girault <[email protected]>
[[email protected]: Isolate this change from a bigger commit]
Signed-off-by: Miquel Raynal <[email protected]>
---
net/Kconfig | 1 -
net/ieee802154/Kconfig | 1 +
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/Kconfig b/net/Kconfig
index 0da89d09ffa6..a5e31078fd14 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -228,7 +228,6 @@ source "net/x25/Kconfig"
source "net/lapb/Kconfig"
source "net/phonet/Kconfig"
source "net/6lowpan/Kconfig"
-source "net/mac802154/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
source "net/dns_resolver/Kconfig"
diff --git a/net/ieee802154/Kconfig b/net/ieee802154/Kconfig
index 31aed75fe62d..7e4b1d49d445 100644
--- a/net/ieee802154/Kconfig
+++ b/net/ieee802154/Kconfig
@@ -36,6 +36,7 @@ config IEEE802154_SOCKET
for 802.15.4 dataframes. Also RAW socket interface to build MAC
header from userspace.
+source "net/mac802154/Kconfig"
source "net/ieee802154/6lowpan/Kconfig"
endif
--
2.27.0
From: David Girault <[email protected]>
While not being absolutely needed, it at least explain the mode vs. enum
fields.
Signed-off-by: David Girault <[email protected]>
[[email protected]: Isolate this change from a bigger commit and
reword the comment]
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index f8ea3d519865..9295615ed019 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -29,6 +29,16 @@ struct ieee802154_llsec_key_id;
struct ieee802154_llsec_key;
#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
+/**
+ * struct ieee802154_addr - IEEE802.15.4 device address
+ * @mode: Address mode from frame header. Can be one of:
+ * - @IEEE802154_ADDR_NONE
+ * - @IEEE802154_ADDR_SHORT
+ * - @IEEE802154_ADDR_LONG
+ * @pan_id: The PAN ID this address belongs to
+ * @short_addr: address if @mode is @IEEE802154_ADDR_SHORT
+ * @extended_addr: address if @mode is @IEEE802154_ADDR_LONG
+ */
struct ieee802154_addr {
u8 mode;
__le16 pan_id;
--
2.27.0
Returning -1 does not indicate anything useful.
Use a standard and meaningful error code instead.
Signed-off-by: Miquel Raynal <[email protected]>
---
net/ieee802154/nl802154.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 45e2c9b0505a..bd1015611a7e 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -1459,7 +1459,7 @@ static int nl802154_send_key(struct sk_buff *msg, u32 cmd, u32 portid,
hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
if (!hdr)
- return -1;
+ return -ENOBUFS;
if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
goto nla_put_failure;
@@ -1652,7 +1652,7 @@ static int nl802154_send_device(struct sk_buff *msg, u32 cmd, u32 portid,
hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
if (!hdr)
- return -1;
+ return -ENOBUFS;
if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
goto nla_put_failure;
@@ -1830,7 +1830,7 @@ static int nl802154_send_devkey(struct sk_buff *msg, u32 cmd, u32 portid,
hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
if (!hdr)
- return -1;
+ return -ENOBUFS;
if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
goto nla_put_failure;
@@ -2006,7 +2006,7 @@ static int nl802154_send_seclevel(struct sk_buff *msg, u32 cmd, u32 portid,
hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
if (!hdr)
- return -1;
+ return -ENOBUFS;
if (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex))
goto nla_put_failure;
--
2.27.0
This definition will be used when adding support for scanning and defines
the content of a beacon frame header as in the 802.15.4 specification.
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/ieee802154_netdev.h | 36 +++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index d0d188c3294b..fb6ac354a7b6 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -22,6 +22,42 @@
#include <net/cfg802154.h>
+struct ieee802154_beacon_hdr {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+ u16 beacon_order:4,
+ superframe_order:4,
+ final_cap_slot:4,
+ battery_life_ext:1,
+ reserved0:1,
+ pan_coordinator:1,
+ assoc_permit:1;
+ u8 gts_count:3,
+ gts_reserved:4,
+ gts_permit:1;
+ u8 pend_short_addr_count:3,
+ reserved1:1,
+ pend_ext_addr_count:3,
+ reserved2:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+ u16 assoc_permit:1,
+ pan_coordinator:1,
+ reserved0:1,
+ battery_life_ext:1,
+ final_cap_slot:4,
+ superframe_order:4,
+ beacon_order:4;
+ u8 gts_permit:1,
+ gts_reserved:4,
+ gts_count:3;
+ u8 reserved2:1,
+ pend_ext_addr_count:3,
+ reserved1:1,
+ pend_short_addr_count:3;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
struct ieee802154_sechdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u8 level:3,
--
2.27.0
Let's introduce the basics of PAN management:
- structures defining PANs
- helpers for PANs registration
- helpers discarding old PANs
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 31 ++++++
net/ieee802154/Makefile | 2 +-
net/ieee802154/core.c | 2 +
net/ieee802154/core.h | 26 +++++
net/ieee802154/pan.c | 231 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 291 insertions(+), 1 deletion(-)
create mode 100644 net/ieee802154/pan.c
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 9295615ed019..9c79feac25bf 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -48,6 +48,24 @@ struct ieee802154_addr {
};
};
+/**
+ * struct ieee802154_pan_desc - PAN descriptor information
+ * @coord: PAN ID and coordinator address
+ * @page: page this PAN is on
+ * @channel: channel this PAN is on
+ * @superframe_spec: SuperFrame specification as received
+ * @link_quality: link quality indicator at which the beacon was received
+ * @gts_permit: the PAN coordinator accepts GTS requests
+ */
+struct ieee802154_pan_desc {
+ struct ieee802154_addr *coord;
+ u8 page;
+ u8 channel;
+ u16 superframe_spec;
+ u8 link_quality;
+ bool gts_permit;
+};
+
struct cfg802154_ops {
struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
const char *name,
@@ -467,4 +485,17 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
void ieee802154_set_symbol_duration(struct wpan_phy *phy);
+/**
+ * cfg802154_record_pan - Advertize a new PAN following a beacon's reception
+ * @wpan_phy: PHY receiving the beacon
+ * @pan: PAN descriptor
+ *
+ * Tells the internal pan management layer to either register this PAN if it is
+ * new or at least update its entry if already discovered.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int cfg802154_record_pan(struct wpan_phy *wpan_phy,
+ struct ieee802154_pan_desc *pan);
+
#endif /* __NET_CFG802154_H */
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index f05b7bdae2aa..6b7c66de730d 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -4,7 +4,7 @@ obj-$(CONFIG_IEEE802154_SOCKET) += ieee802154_socket.o
obj-y += 6lowpan/
ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \
- header_ops.o sysfs.o nl802154.o trace.o
+ header_ops.o sysfs.o nl802154.o pan.o trace.o
ieee802154_socket-y := socket.o
CFLAGS_trace.o := -I$(src)
diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c
index de259b5170ab..0f73e0571883 100644
--- a/net/ieee802154/core.c
+++ b/net/ieee802154/core.c
@@ -115,6 +115,8 @@ wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size)
kfree(rdev);
return NULL;
}
+ spin_lock_init(&rdev->pan_lock);
+ INIT_LIST_HEAD(&rdev->pan_list);
/* atomic_inc_return makes it start at 1, make it start at 0 */
rdev->wpan_phy_idx--;
diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h
index a0cf6feffc6a..0d08d2f79ab9 100644
--- a/net/ieee802154/core.h
+++ b/net/ieee802154/core.h
@@ -22,6 +22,14 @@ struct cfg802154_registered_device {
struct list_head wpan_dev_list;
int devlist_generation, wpan_dev_id;
+ /* pan management */
+ spinlock_t pan_lock;
+ struct list_head pan_list;
+ unsigned int max_pan_entries;
+ unsigned int pan_expiration;
+ unsigned int pan_entries;
+ unsigned int pan_generation;
+
/* must be last because of the way we do wpan_phy_priv(),
* and it should at least be aligned to NETDEV_ALIGN
*/
@@ -39,6 +47,17 @@ wpan_phy_to_rdev(struct wpan_phy *wpan_phy)
extern struct list_head cfg802154_rdev_list;
extern int cfg802154_rdev_list_generation;
+struct cfg802154_internal_pan {
+ struct list_head list;
+ unsigned long discovery_ts;
+ struct ieee802154_pan_desc desc;
+};
+
+/* Always update the list by dropping the expired PANs before iterating */
+#define ieee802154_for_each_pan(pan, rdev) \
+ cfg802154_expire_pans(rdev); \
+ list_for_each_entry((pan), &(rdev)->pan_list, list)
+
int cfg802154_switch_netns(struct cfg802154_registered_device *rdev,
struct net *net);
/* free object */
@@ -49,4 +68,11 @@ struct wpan_phy *wpan_phy_idx_to_wpan_phy(int wpan_phy_idx);
u32 cfg802154_get_supported_chans(struct wpan_phy *phy, unsigned int page);
+void cfg802154_set_max_pan_entries(struct cfg802154_registered_device *rdev,
+ unsigned int max);
+void cfg802154_set_pans_expiration(struct cfg802154_registered_device *rdev,
+ unsigned int exp_time_s);
+void cfg802154_expire_pans(struct cfg802154_registered_device *rdev);
+void cfg802154_flush_pans(struct cfg802154_registered_device *rdev);
+
#endif /* __IEEE802154_CORE_H */
diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
new file mode 100644
index 000000000000..1ea15ea1b3bd
--- /dev/null
+++ b/net/ieee802154/pan.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IEEE 802.15.4 PAN management
+ *
+ * Copyright (C) Qorvo, 2021
+ * Authors:
+ * - David Girault <[email protected]>
+ * - Miquel Raynal <[email protected]>
+ */
+
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+#include <net/cfg802154.h>
+#include <net/af_ieee802154.h>
+
+#include "ieee802154.h"
+#include "core.h"
+
+static struct cfg802154_internal_pan *
+cfg802154_alloc_pan(struct ieee802154_pan_desc *desc)
+{
+ struct cfg802154_internal_pan *new;
+ struct ieee802154_addr *coord;
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
+ return ERR_PTR(-ENOMEM);
+
+ coord = kzalloc(sizeof(*coord), GFP_KERNEL);
+ if (!coord) {
+ kfree(new);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ new->discovery_ts = jiffies;
+ new->desc = *desc;
+
+ *coord = *desc->coord;
+ new->desc.coord = coord;
+
+ return new;
+}
+
+static void cfg802154_free_pan(struct cfg802154_internal_pan *pan)
+{
+ kfree(pan->desc.coord);
+ kfree(pan);
+}
+
+static void cfg802154_unlink_pan(struct cfg802154_registered_device *rdev,
+ struct cfg802154_internal_pan *pan)
+{
+ lockdep_assert_held(&rdev->pan_lock);
+
+ list_del(&pan->list);
+ cfg802154_free_pan(pan);
+ rdev->pan_entries--;
+ rdev->pan_generation++;
+}
+
+static void cfg802154_link_pan(struct cfg802154_registered_device *rdev,
+ struct cfg802154_internal_pan *pan)
+{
+ lockdep_assert_held(&rdev->pan_lock);
+
+ list_add_tail(&pan->list, &rdev->pan_list);
+ rdev->pan_entries++;
+ rdev->pan_generation++;
+}
+
+void cfg802154_set_max_pan_entries(struct cfg802154_registered_device *rdev,
+ unsigned int max)
+{
+ lockdep_assert_held(&rdev->pan_lock);
+
+ rdev->max_pan_entries = max;
+}
+EXPORT_SYMBOL(cfg802154_set_max_pan_entries);
+
+static bool
+cfg802154_need_to_expire_pans(struct cfg802154_registered_device *rdev)
+{
+ if (!rdev->max_pan_entries)
+ return false;
+
+ if (rdev->pan_entries > rdev->max_pan_entries)
+ return true;
+
+ return false;
+}
+
+void cfg802154_set_pans_expiration(struct cfg802154_registered_device *rdev,
+ unsigned int exp_time_s)
+{
+ lockdep_assert_held(&rdev->pan_lock);
+
+ rdev->pan_expiration = exp_time_s * HZ;
+}
+EXPORT_SYMBOL(cfg802154_set_pans_expiration);
+
+void cfg802154_expire_pans(struct cfg802154_registered_device *rdev)
+{
+ struct cfg802154_internal_pan *pan, *tmp;
+ unsigned long expiration_time;
+
+ lockdep_assert_held(&rdev->pan_lock);
+
+ if (!rdev->pan_expiration)
+ return;
+
+ expiration_time = jiffies - rdev->pan_expiration;
+ list_for_each_entry_safe(pan, tmp, &rdev->pan_list, list) {
+ if (!time_after(expiration_time, pan->discovery_ts))
+ continue;
+
+ cfg802154_unlink_pan(rdev, pan);
+ }
+}
+EXPORT_SYMBOL(cfg802154_expire_pans);
+
+static void cfg802154_expire_oldest_pan(struct cfg802154_registered_device *rdev)
+{
+ struct cfg802154_internal_pan *pan, *oldest;
+
+ lockdep_assert_held(&rdev->pan_lock);
+
+ if (WARN_ON(list_empty(&rdev->pan_list)))
+ return;
+
+ oldest = list_first_entry(&rdev->pan_list,
+ struct cfg802154_internal_pan, list);
+
+ list_for_each_entry(pan, &rdev->pan_list, list) {
+ if (!time_before(oldest->discovery_ts, pan->discovery_ts))
+ oldest = pan;
+ }
+
+ cfg802154_unlink_pan(rdev, oldest);
+}
+
+void cfg802154_flush_pans(struct cfg802154_registered_device *rdev)
+{
+ struct cfg802154_internal_pan *pan, *tmp;
+
+ lockdep_assert_held(&rdev->pan_lock);
+
+ list_for_each_entry_safe(pan, tmp, &rdev->pan_list, list)
+ cfg802154_unlink_pan(rdev, pan);
+}
+EXPORT_SYMBOL(cfg802154_flush_pans);
+
+static bool cfg802154_same_pan(struct ieee802154_pan_desc *a,
+ struct ieee802154_pan_desc *b)
+{
+ int ret;
+
+ if (a->page != b->page)
+ return false;
+
+ if (a->channel != b->channel)
+ return false;
+
+ ret = memcmp(&a->coord->pan_id, &b->coord->pan_id,
+ sizeof(a->coord->pan_id));
+ if (ret)
+ return false;
+
+ if (a->coord->mode != b->coord->mode)
+ return false;
+
+ if (a->coord->mode == IEEE802154_ADDR_SHORT)
+ ret = memcmp(&a->coord->short_addr, &b->coord->short_addr,
+ IEEE802154_SHORT_ADDR_LEN);
+ else
+ ret = memcmp(&a->coord->extended_addr, &b->coord->extended_addr,
+ IEEE802154_EXTENDED_ADDR_LEN);
+
+ return true;
+}
+
+static struct cfg802154_internal_pan *
+cfg802154_find_matching_pan(struct cfg802154_registered_device *rdev,
+ struct cfg802154_internal_pan *tmp)
+{
+ struct cfg802154_internal_pan *pan;
+
+ list_for_each_entry(pan, &rdev->pan_list, list) {
+ if (cfg802154_same_pan(&pan->desc, &tmp->desc))
+ return pan;
+ }
+
+ return NULL;
+}
+
+static void cfg802154_pan_update(struct cfg802154_registered_device *rdev,
+ struct cfg802154_internal_pan *new)
+{
+ struct cfg802154_internal_pan *found;
+
+ spin_lock_bh(&rdev->pan_lock);
+
+ found = cfg802154_find_matching_pan(rdev, new);
+ if (found)
+ cfg802154_unlink_pan(rdev, found);
+
+ if (unlikely(cfg802154_need_to_expire_pans(rdev)))
+ cfg802154_expire_oldest_pan(rdev);
+
+ cfg802154_link_pan(rdev, new);
+
+ spin_unlock_bh(&rdev->pan_lock);
+}
+
+int cfg802154_record_pan(struct wpan_phy *wpan_phy,
+ struct ieee802154_pan_desc *desc)
+{
+ struct cfg802154_registered_device *rdev = wpan_phy_to_rdev(wpan_phy);
+ struct cfg802154_internal_pan *new;
+
+ new = cfg802154_alloc_pan(desc);
+ if (IS_ERR(new))
+ return (PTR_ERR(new));
+
+ cfg802154_pan_update(rdev, new);
+
+ return 0;
+}
+EXPORT_SYMBOL(cfg802154_record_pan);
--
2.27.0
A 802.15.4 frame can be of different types, here is a definition
matching the specification. This enumeration will be soon be used when
adding scanning support.
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/ieee802154_netdev.h | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index fb6ac354a7b6..45dff5d11bc8 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -105,6 +105,17 @@ struct ieee802154_hdr_fc {
#endif
};
+enum ieee802154_frame_type {
+ IEEE802154_BEACON_FRAME,
+ IEEE802154_DATA_FRAME,
+ IEEE802154_ACKNOWLEDGEMENT_FRAME,
+ IEEE802154_MAC_COMMAND_FRAME,
+ IEEE802154_RESERVED_FRAME,
+ IEEE802154_MULTIPURPOSE_FRAME,
+ IEEE802154_FRAGMENT_FRAME,
+ IEEE802154_EXTENDED_FRAME,
+};
+
struct ieee802154_hdr {
struct ieee802154_hdr_fc fc;
u8 seq;
--
2.27.0
Implement the core hooks in order to provide the softMAC layer support
for sending beacons. Besides being able to test the full passive
scanning procedure, this will also be used when defining PAN coordinator
status, in order to give a device the right to answer received
BEACON_REQ.
Changing the channels is prohibited while a beacon operation is
ongoing.
The implementation uses a workqueue triggered at a certain interval
depending on the symbol duration for the current channel and the
interval order provided.
Sending beacons in response to an active scan request is not
yet supported.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/ieee802154_netdev.h | 24 +++++++
net/ieee802154/header_ops.c | 29 ++++++++
net/mac802154/cfg.c | 41 ++++++++++-
net/mac802154/ieee802154_i.h | 13 ++++
net/mac802154/main.c | 2 +
net/mac802154/scan.c | 119 ++++++++++++++++++++++++++++++++
6 files changed, 226 insertions(+), 2 deletions(-)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index 45dff5d11bc8..f7716aeec93b 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -116,6 +116,21 @@ enum ieee802154_frame_type {
IEEE802154_EXTENDED_FRAME,
};
+enum ieee802154_frame_version {
+ IEEE802154_2003_STD,
+ IEEE802154_2006_STD,
+ IEEE802154_STD,
+ IEEE802154_RESERVED_STD,
+ IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD,
+};
+
+enum ieee802154_addressing_mode {
+ IEEE802154_NO_ADDRESSING,
+ IEEE802154_RESERVED,
+ IEEE802154_SHORT_ADDRESSING,
+ IEEE802154_EXTENDED_ADDRESSING,
+};
+
struct ieee802154_hdr {
struct ieee802154_hdr_fc fc;
u8 seq;
@@ -124,6 +139,11 @@ struct ieee802154_hdr {
struct ieee802154_sechdr sec;
};
+struct ieee802154_beacon_frame {
+ struct ieee802154_hdr mhr;
+ struct ieee802154_beacon_hdr mac_pl;
+};
+
/* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
* the contents of hdr will be, and the actual value of those bits in
* hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
@@ -149,6 +169,10 @@ int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
*/
int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
+/* pushes a beacon frame into an skb */
+int ieee802154_beacon_push(struct sk_buff *skb,
+ struct ieee802154_beacon_frame *beacon);
+
int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
static inline int
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c
index af337cf62764..bab710aa36f9 100644
--- a/net/ieee802154/header_ops.c
+++ b/net/ieee802154/header_ops.c
@@ -6,6 +6,7 @@
* Phoebe Buckheister <[email protected]>
*/
+#include <linux/crc-ccitt.h>
#include <linux/ieee802154.h>
#include <net/mac802154.h>
@@ -120,6 +121,34 @@ ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr)
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
+int ieee802154_beacon_push(struct sk_buff *skb,
+ struct ieee802154_beacon_frame *beacon)
+{
+ struct ieee802154_beacon_hdr *mac_pl = &beacon->mac_pl;
+ struct ieee802154_hdr *mhr = &beacon->mhr;
+ u16 crc;
+ int ret;
+
+ skb_reserve(skb, sizeof(*mhr));
+ ret = ieee802154_hdr_push(skb, mhr);
+ if (ret < 0)
+ return ret;
+
+ skb_reset_mac_header(skb);
+ skb->mac_len = ret;
+
+ skb_put_data(skb, mac_pl, sizeof(*mac_pl));
+
+ if (mac_pl->pend_short_addr_count || mac_pl->pend_ext_addr_count)
+ return -EOPNOTSUPP;
+
+ crc = crc_ccitt(0, skb->data, skb->len);
+ put_unaligned_le16(crc, skb_put(skb, 2));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee802154_beacon_push);
+
static int
ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan,
struct ieee802154_addr *addr)
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index c1e7bbea3058..afba02c31850 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -109,8 +109,10 @@ int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
ASSERT_RTNL();
- /* Refuse to change channels during a scanning operation */
- if (mac802154_scan_is_ongoing(local))
+ /* Refuse to change channels during a scanning operation or when a
+ * beacons request is ongoing.
+ */
+ if (mac802154_scan_is_ongoing(local) || local->ongoing_beacons_request)
return -EBUSY;
ret = drv_set_channel(local, page, channel);
@@ -305,6 +307,39 @@ static int mac802154_abort_scan(struct wpan_phy *wpan_phy,
return ret;
}
+static int mac802154_send_beacons(struct wpan_phy *wpan_phy,
+ struct cfg802154_beacons_request *request)
+{
+ struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+ struct ieee802154_sub_if_data *sdata;
+ int ret;
+
+ sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(request->wpan_dev);
+
+ ASSERT_RTNL();
+
+ mutex_lock(&local->beacons_lock);
+ ret = mac802154_send_beacons_locked(sdata, request);
+ mutex_unlock(&local->beacons_lock);
+
+ return ret;
+}
+
+static int mac802154_stop_beacons(struct wpan_phy *wpan_phy,
+ struct wpan_dev *wpan_dev)
+{
+ struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+ int ret;
+
+ ASSERT_RTNL();
+
+ mutex_lock(&local->beacons_lock);
+ ret = mac802154_stop_beacons_locked(local);
+ mutex_unlock(&local->beacons_lock);
+
+ return ret;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static void
ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
@@ -514,6 +549,8 @@ const struct cfg802154_ops mac802154_config_ops = {
.set_ackreq_default = ieee802154_set_ackreq_default,
.trigger_scan = mac802154_trigger_scan,
.abort_scan = mac802154_abort_scan,
+ .send_beacons = mac802154_send_beacons,
+ .stop_beacons = mac802154_stop_beacons,
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
.get_llsec_table = ieee802154_get_llsec_table,
.lock_llsec_table = ieee802154_lock_llsec_table,
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 5cc3ac8fd4a1..4feb9181ff4f 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -57,6 +57,14 @@ struct ieee802154_local {
struct ieee802154_sub_if_data __rcu *scan_sdata;
struct delayed_work scan_work;
+ /* Beacons handling */
+ bool ongoing_beacons_request;
+ struct mutex beacons_lock;
+ unsigned int beacons_interval;
+ struct delayed_work beacons_work;
+ struct ieee802154_sub_if_data __rcu *beacons_sdata;
+ struct ieee802154_beacon_frame beacon;
+
bool started;
bool suspended;
@@ -189,6 +197,11 @@ static inline bool mac802154_scan_is_ongoing(struct ieee802154_local *local)
return atomic_read(&local->scanning);
}
+void mac802154_beacons_work(struct work_struct *work);
+int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
+ struct cfg802154_beacons_request *request);
+int mac802154_stop_beacons_locked(struct ieee802154_local *local);
+
/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 09e2fc6848cb..f342c7c5165e 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -91,6 +91,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
INIT_LIST_HEAD(&local->interfaces);
mutex_init(&local->iflist_mtx);
mutex_init(&local->scan_lock);
+ mutex_init(&local->beacons_lock);
tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
@@ -98,6 +99,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_work);
+ INIT_DELAYED_WORK(&local->beacons_work, mac802154_beacons_work);
/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 7be63d73caa9..091cf6fdff41 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -17,6 +17,13 @@
#include "driver-ops.h"
#include "../ieee802154/nl802154.h"
+#define IEEE802154_BEACON_MHR_SZ 13
+#define IEEE802154_BEACON_PL_SZ 4
+#define IEEE802154_CRC_SZ 2
+#define IEEE802154_BEACON_SKB_SZ (IEEE802154_BEACON_MHR_SZ + \
+ IEEE802154_BEACON_PL_SZ + \
+ IEEE802154_CRC_SZ)
+
static bool mac802154_check_promiscuous(struct ieee802154_local *local)
{
struct ieee802154_sub_if_data *sdata;
@@ -104,6 +111,86 @@ static unsigned int mac802154_scan_get_channel_time(u8 duration_order,
(BIT(duration_order) + 1));
}
+int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
+ struct cfg802154_beacons_request *request)
+{
+ struct ieee802154_local *local = sdata->local;
+
+ lockdep_assert_held(&local->beacons_lock);
+
+ if (local->ongoing_beacons_request)
+ return -EBUSY;
+
+ local->ongoing_beacons_request = true;
+
+ memset(&local->beacon, 0, sizeof(local->beacon));
+ local->beacon.mhr.fc.type = IEEE802154_BEACON_FRAME;
+ local->beacon.mhr.fc.security_enabled = 0;
+ local->beacon.mhr.fc.frame_pending = 0;
+ local->beacon.mhr.fc.ack_request = 0;
+ local->beacon.mhr.fc.intra_pan = 0;
+ local->beacon.mhr.fc.dest_addr_mode = IEEE802154_NO_ADDRESSING;
+ local->beacon.mhr.fc.version = IEEE802154_2003_STD;
+ local->beacon.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING;
+ atomic_set(&request->wpan_dev->bsn, -1);
+ local->beacon.mhr.source.mode = IEEE802154_ADDR_LONG;
+ local->beacon.mhr.source.pan_id = cpu_to_le16(request->wpan_dev->pan_id);
+ local->beacon.mhr.source.extended_addr = cpu_to_le64(request->wpan_dev->extended_addr);
+ local->beacon.mac_pl.beacon_order = request->interval;
+ local->beacon.mac_pl.superframe_order = request->interval;
+ local->beacon.mac_pl.final_cap_slot = 0xf;
+ local->beacon.mac_pl.battery_life_ext = 0;
+ local->beacon.mac_pl.pan_coordinator = 1;
+ local->beacon.mac_pl.assoc_permit = 1;
+
+ rcu_assign_pointer(local->beacons_sdata, sdata);
+
+ /* Start the beacon work */
+ local->beacons_interval =
+ mac802154_scan_get_channel_time(request->interval,
+ request->wpan_phy->symbol_duration);
+ ieee802154_queue_delayed_work(&local->hw, &local->beacons_work, 0);
+
+ return 0;
+}
+
+int mac802154_stop_beacons_locked(struct ieee802154_local *local)
+{
+ lockdep_assert_held(&local->beacons_lock);
+
+ if (!local->ongoing_beacons_request)
+ return -ESRCH;
+
+ local->ongoing_beacons_request = false;
+ cancel_delayed_work(&local->beacons_work);
+
+ return 0;
+}
+
+static int mac802154_scan_send_beacon_locked(struct ieee802154_local *local,
+ struct wpan_dev *wpan_dev)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ lockdep_assert_held(&local->beacons_lock);
+
+ /* Update the sequence number */
+ local->beacon.mhr.seq = atomic_inc_return(&wpan_dev->bsn);
+
+ skb = alloc_skb(IEEE802154_BEACON_SKB_SZ, GFP_KERNEL);
+ if (!skb)
+ return -ENOBUFS;
+
+ ret = ieee802154_beacon_push(skb, &local->beacon);
+ if (ret) {
+ kfree_skb(skb);
+ return ret;
+ }
+
+ return drv_xmit_async(local, skb);
+}
+
void mac802154_scan_work(struct work_struct *work)
{
struct ieee802154_local *local =
@@ -205,6 +292,38 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
return 0;
}
+void mac802154_beacons_work(struct work_struct *work)
+{
+ struct ieee802154_local *local =
+ container_of(work, struct ieee802154_local, beacons_work.work);
+ struct ieee802154_sub_if_data *sdata;
+ struct wpan_dev *wpan_dev;
+ int ret;
+
+ mutex_lock(&local->beacons_lock);
+
+ if (!local->ongoing_beacons_request)
+ goto unlock_mutex;
+
+ if (local->suspended)
+ goto queue_work;
+
+ sdata = rcu_dereference_protected(local->beacons_sdata,
+ lockdep_is_held(&local->beacons_lock));
+ wpan_dev = &sdata->wpan_dev;
+
+ ret = mac802154_scan_send_beacon_locked(local, wpan_dev);
+ if (ret)
+ pr_err("Error when transmitting beacon (%d)\n", ret);
+
+queue_work:
+ ieee802154_queue_delayed_work(&local->hw, &local->beacons_work,
+ local->beacons_interval);
+
+unlock_mutex:
+ mutex_unlock(&local->beacons_lock);
+}
+
int mac802154_scan_process_beacon(struct ieee802154_local *local,
struct sk_buff *skb)
{
--
2.27.0
Active scan support is based on the current passive scan support,
cheered up with beacon requests sent after every channel change.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/ieee802154_netdev.h | 14 ++++++++-
net/ieee802154/header_ops.c | 25 +++++++++++++++++
net/mac802154/ieee802154_i.h | 1 +
net/mac802154/scan.c | 50 +++++++++++++++++++++++++++++++--
4 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index f7716aeec93b..1bf1a4e508a2 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -58,6 +58,11 @@ struct ieee802154_beacon_hdr {
#endif
} __packed;
+struct ieee802154_mac_cmd_pl {
+ u8 cmd_id;
+ /* TODO: content depending on the cmd_id */
+} __packed;
+
struct ieee802154_sechdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
u8 level:3,
@@ -139,6 +144,11 @@ struct ieee802154_hdr {
struct ieee802154_sechdr sec;
};
+struct ieee802154_beacon_req_frame {
+ struct ieee802154_hdr mhr;
+ struct ieee802154_mac_cmd_pl mac_pl;
+};
+
struct ieee802154_beacon_frame {
struct ieee802154_hdr mhr;
struct ieee802154_beacon_hdr mac_pl;
@@ -169,7 +179,9 @@ int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
*/
int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
-/* pushes a beacon frame into an skb */
+/* pushes a beacon_req or a beacon frame into an skb */
+int ieee802154_beacon_req_push(struct sk_buff *skb,
+ struct ieee802154_beacon_req_frame *breq);
int ieee802154_beacon_push(struct sk_buff *skb,
struct ieee802154_beacon_frame *beacon);
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c
index bab710aa36f9..c31a9e429a14 100644
--- a/net/ieee802154/header_ops.c
+++ b/net/ieee802154/header_ops.c
@@ -121,6 +121,31 @@ ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr)
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
+int ieee802154_beacon_req_push(struct sk_buff *skb,
+ struct ieee802154_beacon_req_frame *breq)
+{
+ struct ieee802154_mac_cmd_pl *mac_pl = &breq->mac_pl;
+ struct ieee802154_hdr *mhr = &breq->mhr;
+ u16 crc;
+ int ret;
+
+ skb_reserve(skb, sizeof(*mhr));
+ ret = ieee802154_hdr_push(skb, mhr);
+ if (ret < 0)
+ return ret;
+
+ skb_reset_mac_header(skb);
+ skb->mac_len = ret;
+
+ skb_put_data(skb, mac_pl, sizeof(*mac_pl));
+
+ crc = crc_ccitt(0, skb->data, skb->len);
+ put_unaligned_le16(crc, skb_put(skb, 2));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee802154_beacon_req_push);
+
int ieee802154_beacon_push(struct sk_buff *skb,
struct ieee802154_beacon_frame *beacon)
{
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 4feb9181ff4f..19c840500bd8 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -56,6 +56,7 @@ struct ieee802154_local {
struct cfg802154_scan_request __rcu *scan_req;
struct ieee802154_sub_if_data __rcu *scan_sdata;
struct delayed_work scan_work;
+ struct ieee802154_beacon_req_frame beacon_req;
/* Beacons handling */
bool ongoing_beacons_request;
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 091cf6fdff41..a3ff65d5bb7a 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -19,10 +19,15 @@
#define IEEE802154_BEACON_MHR_SZ 13
#define IEEE802154_BEACON_PL_SZ 4
+#define IEEE802154_BEACON_REQ_MHR_SZ 7
+#define IEEE802154_BEACON_REQ_PL_SZ 1
#define IEEE802154_CRC_SZ 2
#define IEEE802154_BEACON_SKB_SZ (IEEE802154_BEACON_MHR_SZ + \
IEEE802154_BEACON_PL_SZ + \
IEEE802154_CRC_SZ)
+#define IEEE802154_BEACON_REQ_SKB_SZ (IEEE802154_BEACON_REQ_MHR_SZ + \
+ IEEE802154_BEACON_REQ_PL_SZ + \
+ IEEE802154_CRC_SZ)
static bool mac802154_check_promiscuous(struct ieee802154_local *local)
{
@@ -167,6 +172,41 @@ int mac802154_stop_beacons_locked(struct ieee802154_local *local)
return 0;
}
+static int mac802154_scan_prepare_beacon_req(struct ieee802154_local *local)
+{
+ memset(&local->beacon_req, 0, sizeof(local->beacon_req));
+ local->beacon_req.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD;
+ local->beacon_req.mhr.fc.dest_addr_mode = IEEE802154_SHORT_ADDRESSING;
+ local->beacon_req.mhr.fc.version = IEEE802154_2003_STD;
+ local->beacon_req.mhr.fc.source_addr_mode = IEEE802154_NO_ADDRESSING;
+ local->beacon_req.mhr.dest.mode = IEEE802154_ADDR_SHORT;
+ local->beacon_req.mhr.dest.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+ local->beacon_req.mhr.dest.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+ local->beacon_req.mac_pl.cmd_id = IEEE802154_CMD_BEACON_REQ;
+
+ return 0;
+}
+
+static int mac802154_scan_send_beacon_req_locked(struct ieee802154_local *local)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ lockdep_assert_held(&local->scan_lock);
+
+ skb = alloc_skb(IEEE802154_BEACON_REQ_SKB_SZ, GFP_KERNEL);
+ if (!skb)
+ return -ENOBUFS;
+
+ ret = ieee802154_beacon_req_push(skb, &local->beacon_req);
+ if (ret) {
+ kfree_skb(skb);
+ return ret;
+ }
+
+ return drv_xmit_async(local, skb);
+}
+
static int mac802154_scan_send_beacon_locked(struct ieee802154_local *local,
struct wpan_dev *wpan_dev)
{
@@ -236,6 +276,9 @@ void mac802154_scan_work(struct work_struct *work)
ieee802154_set_symbol_duration(local->phy);
} while (ret);
+ if (scan_req->type == NL802154_SCAN_ACTIVE)
+ mac802154_scan_send_beacon_req_locked(local);
+
queue_work:
scan_duration = mac802154_scan_get_channel_time(scan_req->duration,
local->phy->symbol_duration);
@@ -262,8 +305,8 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
if (mac802154_scan_is_ongoing(local))
return -EBUSY;
- /* TODO: support other scanning type */
- if (request->type != NL802154_SCAN_PASSIVE)
+ if (request->type != NL802154_SCAN_PASSIVE &&
+ request->type != NL802154_SCAN_ACTIVE)
return -EOPNOTSUPP;
/* Store scanning parameters */
@@ -276,6 +319,9 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
else
local->scan_addr = cpu_to_le64(get_unaligned_be64(sdata->dev->dev_addr));
+ if (request->type == NL802154_SCAN_ACTIVE)
+ mac802154_scan_prepare_beacon_req(local);
+
local->scan_channel_idx = -1;
atomic_set(&local->scanning, 1);
--
2.27.0
Let's create a couple of driver hooks in order to tell the device
drivers that a scan is ongoing, allowing them to eventually apply any
needed configuration, or in the worst case to refuse the operation if it
is not supported. These hooks are optional and not implementing them
does not prevent the scan operation to happen. Returning an error from
these implementations will however shut down the scan entirely.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/mac802154.h | 12 ++++++++++++
net/mac802154/driver-ops.h | 29 +++++++++++++++++++++++++++++
net/mac802154/scan.c | 7 +++++++
net/mac802154/trace.h | 28 ++++++++++++++++++++++++++++
4 files changed, 76 insertions(+)
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 19bfbf591ea1..9b852c02db88 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -204,6 +204,15 @@ enum ieee802154_hw_flags {
*
* set_promiscuous_mode
* Enables or disable promiscuous mode.
+ *
+ * enter_scan_mode
+ * Enters the scan mode, may then refuse certain operations.
+ * Can be NULL, if the driver has no internal configuration to do.
+ * Returns either zero, or negative errno.
+ *
+ * exit_scan_mode
+ * Exits the scan mode and returns to a fully functioning state.
+ * Should only be provided if ->enter_scan_mode() is populated.
*/
struct ieee802154_ops {
struct module *owner;
@@ -230,6 +239,9 @@ struct ieee802154_ops {
s8 retries);
int (*set_promiscuous_mode)(struct ieee802154_hw *hw,
const bool on);
+ int (*enter_scan_mode)(struct ieee802154_hw *hw,
+ struct cfg802154_scan_request *request);
+ void (*exit_scan_mode)(struct ieee802154_hw *hw);
};
/**
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h
index d23f0db98015..9da2325d8346 100644
--- a/net/mac802154/driver-ops.h
+++ b/net/mac802154/driver-ops.h
@@ -282,4 +282,33 @@ drv_set_promiscuous_mode(struct ieee802154_local *local, bool on)
return ret;
}
+static inline int drv_enter_scan_mode(struct ieee802154_local *local,
+ struct cfg802154_scan_request *request)
+{
+ int ret;
+
+ might_sleep();
+
+ if (!local->ops->enter_scan_mode || !local->ops->exit_scan_mode)
+ return 0;
+
+ trace_802154_drv_enter_scan_mode(local, request);
+ ret = local->ops->enter_scan_mode(&local->hw, request);
+ trace_802154_drv_return_int(local, ret);
+
+ return ret;
+}
+
+static inline void drv_exit_scan_mode(struct ieee802154_local *local)
+{
+ might_sleep();
+
+ if (!local->ops->enter_scan_mode || !local->ops->exit_scan_mode)
+ return;
+
+ trace_802154_drv_exit_scan_mode(local);
+ local->ops->exit_scan_mode(&local->hw);
+ trace_802154_drv_return_void(local);
+}
+
#endif /* __MAC802154_DRIVER_OPS */
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index c9412dfaeb66..a639c53fa3ba 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -103,6 +103,8 @@ int mac802154_abort_scan_locked(struct ieee802154_local *local)
cancel_delayed_work(&local->scan_work);
+ drv_exit_scan_mode(local);
+
return mac802154_end_of_scan(local);
}
@@ -327,6 +329,11 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
else
local->scan_addr = cpu_to_le64(get_unaligned_be64(sdata->dev->dev_addr));
+ /* Let the drivers know about the starting scanning operation */
+ ret = drv_enter_scan_mode(local, request);
+ if (ret)
+ return ret;
+
if (request->type == NL802154_SCAN_ACTIVE)
mac802154_scan_prepare_beacon_req(local);
diff --git a/net/mac802154/trace.h b/net/mac802154/trace.h
index df855c33daf2..9c0a4f07ced1 100644
--- a/net/mac802154/trace.h
+++ b/net/mac802154/trace.h
@@ -264,6 +264,34 @@ TRACE_EVENT(802154_drv_set_promiscuous_mode,
BOOL_TO_STR(__entry->on))
);
+TRACE_EVENT(802154_drv_enter_scan_mode,
+ TP_PROTO(struct ieee802154_local *local,
+ struct cfg802154_scan_request *request),
+ TP_ARGS(local, request),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u8, page)
+ __field(u32, channels)
+ __field(u8, duration)
+ __field(u64, addr)
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->page = request->page;
+ __entry->channels = request->channels;
+ __entry->duration = request->duration;
+ __entry->addr = local->scan_addr;
+ ),
+ TP_printk(LOCAL_PR_FMT ", scan, page: %d, channels: %x, duration %d, addr: 0x%llx",
+ LOCAL_PR_ARG, __entry->page, __entry->channels,
+ __entry->duration, __entry->addr)
+);
+
+DEFINE_EVENT(local_only_evt4, 802154_drv_exit_scan_mode,
+ TP_PROTO(struct ieee802154_local *local),
+ TP_ARGS(local)
+);
+
#endif /* !__MAC802154_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
2.27.0
This involves processing triggering scan requests, abort scan requests,
as well as providing information about if the last scan was finished or
not.
A scan request structure is created to list the requirements.
A netlink multicast scan group is also created for the occasion so that
listeners can only focus on scan activity.
Mac layers may now implement the ->trigger_scan() and ->abort_scan()
hooks.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/linux/ieee802154.h | 3 +
include/net/cfg802154.h | 26 +++++
include/net/nl802154.h | 49 ++++++++
net/ieee802154/core.h | 3 +
net/ieee802154/nl802154.c | 234 +++++++++++++++++++++++++++++++++++++
net/ieee802154/nl802154.h | 4 +
net/ieee802154/rdev-ops.h | 28 +++++
net/ieee802154/trace.h | 40 +++++++
8 files changed, 387 insertions(+)
diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h
index 95c831162212..41178c87c43c 100644
--- a/include/linux/ieee802154.h
+++ b/include/linux/ieee802154.h
@@ -44,6 +44,9 @@
#define IEEE802154_SHORT_ADDR_LEN 2
#define IEEE802154_PAN_ID_LEN 2
+/* Duration in superframe order */
+#define IEEE802154_MAX_SCAN_DURATION 14
+#define IEEE802154_ACTIVE_SCAN_DURATION 15
#define IEEE802154_LIFS_PERIOD 40
#define IEEE802154_SIFS_PERIOD 12
#define IEEE802154_MAX_SIFS_FRAME_SIZE 18
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 9c79feac25bf..2118bfc02d7c 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -66,6 +66,28 @@ struct ieee802154_pan_desc {
bool gts_permit;
};
+/**
+ * struct cfg802154_scan_req - Scan request
+ *
+ * @type: type of scan to be performed
+ * @flags: flags bitfield controlling the operation
+ * @page: page on which to perform the scan
+ * @channels: channels in te %page to be scanned
+ * @duration: time spent on each channel, calculated with:
+ * aBaseSuperframeDuration * (2 ^ duration + 1)
+ * @wpan_dev: the wpan device on which to perform the scan
+ * @wpan_phy: the wpan phy on which to perform the scan
+ */
+struct cfg802154_scan_request {
+ enum nl802154_scan_types type;
+ u32 flags;
+ u8 page;
+ u32 channels;
+ u8 duration;
+ struct wpan_dev *wpan_dev;
+ struct wpan_phy *wpan_phy;
+};
+
struct cfg802154_ops {
struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
const char *name,
@@ -104,6 +126,10 @@ struct cfg802154_ops {
struct wpan_dev *wpan_dev, bool mode);
int (*set_ackreq_default)(struct wpan_phy *wpan_phy,
struct wpan_dev *wpan_dev, bool ackreq);
+ int (*trigger_scan)(struct wpan_phy *wpan_phy,
+ struct cfg802154_scan_request *request);
+ int (*abort_scan)(struct wpan_phy *wpan_phy,
+ struct wpan_dev *wpan_dev);
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
void (*get_llsec_table)(struct wpan_phy *wpan_phy,
struct wpan_dev *wpan_dev,
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 145acb8f2509..51eca3a2b14e 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -58,6 +58,10 @@ enum nl802154_commands {
NL802154_CMD_SET_WPAN_PHY_NETNS,
+ NL802154_CMD_TRIGGER_SCAN,
+ NL802154_CMD_ABORT_SCAN,
+ NL802154_CMD_SCAN_DONE,
+
/* add new commands above here */
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
@@ -133,6 +137,11 @@ enum nl802154_attrs {
NL802154_ATTR_PID,
NL802154_ATTR_NETNS_FD,
+ NL802154_ATTR_SCAN_TYPE,
+ NL802154_ATTR_SCAN_FLAGS,
+ NL802154_ATTR_SCAN_CHANNELS,
+ NL802154_ATTR_SCAN_DURATION,
+
/* add attributes here, update the policy in nl802154.c */
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
@@ -218,6 +227,46 @@ enum nl802154_wpan_phy_capability_attr {
NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1
};
+/**
+ * enum nl802154_scan_types - Scan types
+ *
+ * @__NL802154_SCAN_INVALID: scan type number 0 is reserved
+ * @NL802154_SCAN_ED: An ED scan allows a device to obtain a measure of the peak
+ * energy in each requested channel
+ * @NL802154_SCAN_ACTIVE: Locate any coordinator transmitting Beacon frames using
+ * a Beacon Request command
+ * @NL802154_SCAN_PASSIVE: Locate any coordinator transmitting Beacon frames
+ * @NL802154_SCAN_ORPHAN: Relocate coordinator following a loss of synchronisation
+ * @NL802154_SCAN_ENHANCED_ACTIVE: Same as Active using Enhanced Beacon Request
+ * command instead of Beacon Request command
+ * @NL802154_SCAN_RIT_PASSIVE: Passive scan for RIT Data Request command frames
+ * instead of Beacon frames
+ * @NL802154_SCAN_ATTR_MAX: Maximum SCAN attribute number
+ */
+enum nl802154_scan_types {
+ __NL802154_SCAN_INVALID,
+ NL802154_SCAN_ED,
+ NL802154_SCAN_ACTIVE,
+ NL802154_SCAN_PASSIVE,
+ NL802154_SCAN_ORPHAN,
+ NL802154_SCAN_ENHANCED_ACTIVE,
+ NL802154_SCAN_RIT_PASSIVE,
+
+ /* keep last */
+ NL802154_SCAN_ATTR_MAX,
+};
+
+/**
+ * enum nl802154_scan_flags - Scan request control flags
+ *
+ * @NL802154_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (ie.
+ * a different one for every scan iteration). When the flag is set, full
+ * randomisation is assumed.
+ */
+enum nl802154_scan_flags {
+ NL802154_SCAN_FLAG_RANDOM_ADDR = BIT(0),
+};
+
/**
* enum nl802154_cca_modes - cca modes
*
diff --git a/net/ieee802154/core.h b/net/ieee802154/core.h
index 0d08d2f79ab9..9aa8f88b6920 100644
--- a/net/ieee802154/core.h
+++ b/net/ieee802154/core.h
@@ -30,6 +30,9 @@ struct cfg802154_registered_device {
unsigned int pan_entries;
unsigned int pan_generation;
+ /* scanning */
+ struct cfg802154_scan_request *scan_req;
+
/* must be last because of the way we do wpan_phy_priv(),
* and it should at least be aligned to NETDEV_ALIGN
*/
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index bd1015611a7e..99cbad1f1381 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -26,10 +26,12 @@ static struct genl_family nl802154_fam;
/* multicast groups */
enum nl802154_multicast_groups {
NL802154_MCGRP_CONFIG,
+ NL802154_MCGRP_SCAN,
};
static const struct genl_multicast_group nl802154_mcgrps[] = {
[NL802154_MCGRP_CONFIG] = { .name = "config", },
+ [NL802154_MCGRP_SCAN] = { .name = "scan", },
};
/* returns ERR_PTR values */
@@ -216,6 +218,12 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
[NL802154_ATTR_PID] = { .type = NLA_U32 },
[NL802154_ATTR_NETNS_FD] = { .type = NLA_U32 },
+
+ [NL802154_ATTR_SCAN_TYPE] = { .type = NLA_U8 },
+ [NL802154_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
+ [NL802154_ATTR_SCAN_CHANNELS] = { .type = NLA_U32 },
+ [NL802154_ATTR_SCAN_DURATION] = { .type = NLA_U8 },
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
[NL802154_ATTR_SEC_OUT_LEVEL] = { .type = NLA_U32, },
@@ -1299,6 +1307,216 @@ static int nl802154_wpan_phy_netns(struct sk_buff *skb, struct genl_info *info)
return err;
}
+static int nl802154_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+ struct wpan_phy *wpan_phy = &rdev->wpan_phy;
+ struct cfg802154_scan_request *request;
+ u8 type;
+ int err;
+
+ /* Test iftype and avoid scanning if monitor type. */
+ if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
+ return -EOPNOTSUPP;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->wpan_dev = wpan_dev;
+ request->wpan_phy = wpan_phy;
+
+ type = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_TYPE]);
+ switch (type) {
+ case NL802154_SCAN_ACTIVE:
+ case NL802154_SCAN_PASSIVE:
+ request->type = type;
+ break;
+ default:
+ pr_err("Invalid scan type: %d\n", type);
+ err = -EINVAL;
+ goto free_request;
+ }
+
+ if (info->attrs[NL802154_ATTR_SCAN_FLAGS])
+ request->flags = nla_get_u32(info->attrs[NL802154_ATTR_SCAN_FLAGS]);
+
+ if (info->attrs[NL802154_ATTR_PAGE]) {
+ request->page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
+ if (request->page > IEEE802154_MAX_PAGE) {
+ pr_err("Invalid page %d > %d\n",
+ request->page, IEEE802154_MAX_PAGE);
+ err = -EINVAL;
+ goto free_request;
+ }
+ } else {
+ /* Use current page by default */
+ request->page = wpan_phy->current_page;
+ }
+
+ if (info->attrs[NL802154_ATTR_SCAN_CHANNELS]) {
+ request->channels = nla_get_u32(info->attrs[NL802154_ATTR_SCAN_CHANNELS]);
+ if (request->channels >= BIT(IEEE802154_MAX_CHANNEL + 1)) {
+ pr_err("Invalid channels bitfield %x ≥ %lx\n",
+ request->channels,
+ BIT(IEEE802154_MAX_CHANNEL + 1));
+ err = -EINVAL;
+ goto free_request;
+ }
+ } else {
+ /* Scan all supported channels by default */
+ request->channels = cfg802154_get_supported_chans(wpan_phy,
+ request->page);
+ }
+
+ if (info->attrs[NL802154_ATTR_SCAN_DURATION]) {
+ request->duration = nla_get_u8(info->attrs[NL802154_ATTR_SCAN_DURATION]);
+ if (request->duration > IEEE802154_MAX_SCAN_DURATION) {
+ pr_err("Duration is out of range\n");
+ err = -EINVAL;
+ goto free_request;
+ }
+ } else {
+ /* Use maximum duration order by default */
+ request->duration = IEEE802154_MAX_SCAN_DURATION;
+ }
+
+ err = rdev_trigger_scan(rdev, request);
+ if (err) {
+ pr_err("Failure starting scanning (%d)\n", err);
+ goto free_request;
+ }
+
+ rdev->scan_req = request;
+
+ if (wpan_dev->netdev)
+ dev_hold(wpan_dev->netdev);
+
+ return 0;
+
+free_request:
+ kfree(request);
+
+ return err;
+}
+
+static int nl802154_add_scan_req(struct sk_buff *msg,
+ struct cfg802154_scan_request *req)
+{
+ if (req->type &&
+ nla_put_u8(msg, NL802154_ATTR_SCAN_TYPE, req->type))
+ goto nla_put_failure;
+
+ if (req->flags &&
+ nla_put_u32(msg, NL802154_ATTR_SCAN_FLAGS, req->flags))
+ goto nla_put_failure;
+
+ if (req->page &&
+ nla_put_u8(msg, NL802154_ATTR_PAGE, req->page))
+ goto nla_put_failure;
+
+ if (req->channels &&
+ nla_put_u32(msg, NL802154_ATTR_SCAN_CHANNELS, req->channels))
+ goto nla_put_failure;
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+static int nl802154_prep_scan_msg(struct sk_buff *msg,
+ struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev,
+ u32 portid, u32 seq, int flags, u8 cmd)
+{
+ void *hdr;
+
+ hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
+ if (!hdr)
+ return -ENOBUFS;
+
+ if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx))
+ goto nla_put_failure;
+
+ if (wpan_dev->netdev &&
+ nla_put_u32(msg, NL802154_ATTR_IFINDEX, wpan_dev->netdev->ifindex))
+ goto nla_put_failure;
+
+ if (nla_put_u64_64bit(msg, NL802154_ATTR_WPAN_DEV,
+ wpan_dev_id(wpan_dev), NL802154_ATTR_PAD))
+ goto nla_put_failure;
+
+ if (nl802154_add_scan_req(msg, rdev->scan_req))
+ goto nla_put_failure;
+
+ genlmsg_end(msg, hdr);
+
+ return 0;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+
+ return -EMSGSIZE;
+}
+
+static int nl802154_send_scan_done_msg(struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev)
+{
+ struct sk_buff *msg;
+ int ret;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ ret = nl802154_prep_scan_msg(msg, rdev, wpan_dev, 0, 0, 0,
+ NL802154_CMD_SCAN_DONE);
+ if (ret < 0) {
+ nlmsg_free(msg);
+ return ret;
+ }
+
+ return genlmsg_multicast_netns(&nl802154_fam,
+ wpan_phy_net(&rdev->wpan_phy), msg, 0,
+ NL802154_MCGRP_SCAN, GFP_KERNEL);
+}
+
+int nl802154_send_scan_done(struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev)
+{
+ int err;
+
+ err = nl802154_send_scan_done_msg(rdev, wpan_dev);
+
+ /* Ignore errors when there are no listeners */
+ if (err == -ESRCH)
+ err = 0;
+
+ if (wpan_dev->netdev)
+ dev_put(wpan_dev->netdev);
+
+ kfree(rdev->scan_req);
+ rdev->scan_req = NULL;
+
+ return err;
+}
+EXPORT_SYMBOL(nl802154_send_scan_done);
+
+static int nl802154_abort_scan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+
+ /* Resources will be released in the notification helper above when we
+ * are sure all actions have ended.
+ */
+ return rdev_abort_scan(rdev, wpan_dev);
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2387,6 +2605,22 @@ static const struct genl_ops nl802154_ops[] = {
.internal_flags = NL802154_FLAG_NEED_NETDEV |
NL802154_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL802154_CMD_TRIGGER_SCAN,
+ .doit = nl802154_trigger_scan,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_CHECK_NETDEV_UP |
+ NL802154_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL802154_CMD_ABORT_SCAN,
+ .doit = nl802154_abort_scan,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_CHECK_NETDEV_UP |
+ NL802154_FLAG_NEED_RTNL,
+ },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
{
.cmd = NL802154_CMD_SET_SEC_PARAMS,
diff --git a/net/ieee802154/nl802154.h b/net/ieee802154/nl802154.h
index 8c4b6d08954c..84567cd4ea83 100644
--- a/net/ieee802154/nl802154.h
+++ b/net/ieee802154/nl802154.h
@@ -2,7 +2,11 @@
#ifndef __IEEE802154_NL802154_H
#define __IEEE802154_NL802154_H
+#include "core.h"
+
int nl802154_init(void);
void nl802154_exit(void);
+int nl802154_send_scan_done(struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev);
#endif /* __IEEE802154_NL802154_H */
diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h
index 598f5af49775..e171d74c3251 100644
--- a/net/ieee802154/rdev-ops.h
+++ b/net/ieee802154/rdev-ops.h
@@ -209,6 +209,34 @@ rdev_set_ackreq_default(struct cfg802154_registered_device *rdev,
return ret;
}
+static inline int rdev_trigger_scan(struct cfg802154_registered_device *rdev,
+ struct cfg802154_scan_request *request)
+{
+ int ret;
+
+ if (!rdev->ops->trigger_scan)
+ return -EOPNOTSUPP;
+
+ trace_802154_rdev_trigger_scan(&rdev->wpan_phy, request);
+ ret = rdev->ops->trigger_scan(&rdev->wpan_phy, request);
+ trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+ return ret;
+}
+
+static inline int rdev_abort_scan(struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev)
+{
+ int ret;
+
+ if (!rdev->ops->abort_scan)
+ return -EOPNOTSUPP;
+
+ trace_802154_rdev_abort_scan(&rdev->wpan_phy, wpan_dev);
+ ret = rdev->ops->abort_scan(&rdev->wpan_phy, wpan_dev);
+ trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+ return ret;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
/* TODO this is already a nl802154, so move into ieee802154 */
static inline void
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
index 19c2e5d60e76..e5405f737ded 100644
--- a/net/ieee802154/trace.h
+++ b/net/ieee802154/trace.h
@@ -295,6 +295,46 @@ TRACE_EVENT(802154_rdev_set_ackreq_default,
WPAN_DEV_PR_ARG, BOOL_TO_STR(__entry->ackreq))
);
+TRACE_EVENT(802154_rdev_trigger_scan,
+ TP_PROTO(struct wpan_phy *wpan_phy,
+ struct cfg802154_scan_request *request),
+ TP_ARGS(wpan_phy, request),
+ TP_STRUCT__entry(
+ WPAN_PHY_ENTRY
+ __field(u8, page)
+ __field(u32, channels)
+ __field(u8, duration)
+ ),
+ TP_fast_assign(
+ WPAN_PHY_ASSIGN;
+ __entry->page = request->page;
+ __entry->channels = request->channels;
+ __entry->duration = request->duration;
+ ),
+ TP_printk(WPAN_PHY_PR_FMT ", scan, page: %d, channels: %x, duration %d",
+ WPAN_PHY_PR_ARG, __entry->page, __entry->channels, __entry->duration)
+);
+
+DECLARE_EVENT_CLASS(802154_wdev_template,
+ TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev),
+ TP_ARGS(wpan_phy, wpan_dev),
+ TP_STRUCT__entry(
+ WPAN_PHY_ENTRY
+ WPAN_DEV_ENTRY
+ ),
+ TP_fast_assign(
+ WPAN_PHY_ASSIGN;
+ WPAN_DEV_ASSIGN;
+ ),
+ TP_printk(WPAN_PHY_PR_FMT ", " WPAN_DEV_PR_FMT,
+ WPAN_PHY_PR_ARG, WPAN_DEV_PR_ARG)
+);
+
+DEFINE_EVENT(802154_wdev_template, 802154_rdev_abort_scan,
+ TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev),
+ TP_ARGS(wpan_phy, wpan_dev)
+);
+
TRACE_EVENT(802154_rdev_return_int,
TP_PROTO(struct wpan_phy *wpan_phy, int ret),
TP_ARGS(wpan_phy, ret),
--
2.27.0
Let's create a couple of driver hooks in order to tell the device
drivers that beacons are being sent, allowing them to eventually apply
any needed configuration, or in the worst case to refuse the operation
if it is not supported. These hooks are optional and not implementing
them does not prevent the beacons operation to happen. Returning an
error from these implementations will however shut down the beacons
configuration entirely.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/mac802154.h | 14 ++++++++++++++
net/mac802154/driver-ops.h | 29 +++++++++++++++++++++++++++++
net/mac802154/scan.c | 10 ++++++++++
net/mac802154/trace.h | 21 +++++++++++++++++++++
4 files changed, 74 insertions(+)
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 9b852c02db88..f73b4f4f1025 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -213,6 +213,17 @@ enum ieee802154_hw_flags {
* exit_scan_mode
* Exits the scan mode and returns to a fully functioning state.
* Should only be provided if ->enter_scan_mode() is populated.
+ *
+ * enter_beacons_mode
+ * Enters the beacons mode, the stack will either send beacons at a fixed
+ * rate or upon request depending on the configuration.
+ * Can be NULL, if the driver has no internal configuration to do.
+ * Returns either zero, or negative errno.
+ *
+ * exit_beacons_mode
+ * Exits the beacons mode and returns to a fully functioning state.
+ * Should only be provided if ->enter_beacons_mode() is populated.
+ * Returns either zero, or negative errno.
*/
struct ieee802154_ops {
struct module *owner;
@@ -242,6 +253,9 @@ struct ieee802154_ops {
int (*enter_scan_mode)(struct ieee802154_hw *hw,
struct cfg802154_scan_request *request);
void (*exit_scan_mode)(struct ieee802154_hw *hw);
+ int (*enter_beacons_mode)(struct ieee802154_hw *hw,
+ struct cfg802154_beacons_request *request);
+ void (*exit_beacons_mode)(struct ieee802154_hw *hw);
};
/**
diff --git a/net/mac802154/driver-ops.h b/net/mac802154/driver-ops.h
index 9da2325d8346..fa874088a284 100644
--- a/net/mac802154/driver-ops.h
+++ b/net/mac802154/driver-ops.h
@@ -311,4 +311,33 @@ static inline void drv_exit_scan_mode(struct ieee802154_local *local)
trace_802154_drv_return_void(local);
}
+static inline int drv_enter_beacons_mode(struct ieee802154_local *local,
+ struct cfg802154_beacons_request *request)
+{
+ int ret;
+
+ might_sleep();
+
+ if (!local->ops->enter_beacons_mode || !local->ops->exit_beacons_mode)
+ return 0;
+
+ trace_802154_drv_enter_beacons_mode(local, request);
+ ret = local->ops->enter_beacons_mode(&local->hw, request);
+ trace_802154_drv_return_int(local, ret);
+
+ return ret;
+}
+
+static inline void drv_exit_beacons_mode(struct ieee802154_local *local)
+{
+ might_sleep();
+
+ if (!local->ops->enter_beacons_mode || !local->ops->exit_beacons_mode)
+ return;
+
+ trace_802154_drv_exit_beacons_mode(local);
+ local->ops->exit_beacons_mode(&local->hw);
+ trace_802154_drv_return_void(local);
+}
+
#endif /* __MAC802154_DRIVER_OPS */
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index a639c53fa3ba..bda13448e294 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -122,6 +122,7 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
struct cfg802154_beacons_request *request)
{
struct ieee802154_local *local = sdata->local;
+ int ret;
lockdep_assert_held(&local->beacons_lock);
@@ -130,6 +131,13 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
local->ongoing_beacons_request = true;
+ /* Either let the hardware handle the beacons or handle them manually */
+ ret = drv_enter_beacons_mode(local, request);
+ if (ret) {
+ local->ongoing_beacons_request = false;
+ return ret;
+ }
+
memset(&local->beacon, 0, sizeof(local->beacon));
local->beacon.mhr.fc.type = IEEE802154_BEACON_FRAME;
local->beacon.mhr.fc.security_enabled = 0;
@@ -179,6 +187,8 @@ int mac802154_stop_beacons_locked(struct ieee802154_local *local)
if (local->beacons_interval >= 0)
cancel_delayed_work(&local->beacons_work);
+ drv_exit_beacons_mode(local);
+
return 0;
}
diff --git a/net/mac802154/trace.h b/net/mac802154/trace.h
index 9c0a4f07ced1..93519181045a 100644
--- a/net/mac802154/trace.h
+++ b/net/mac802154/trace.h
@@ -292,6 +292,27 @@ DEFINE_EVENT(local_only_evt4, 802154_drv_exit_scan_mode,
TP_ARGS(local)
);
+TRACE_EVENT(802154_drv_enter_beacons_mode,
+ TP_PROTO(struct ieee802154_local *local,
+ struct cfg802154_beacons_request *request),
+ TP_ARGS(local, request),
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u8, interval)
+ ),
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->interval = request->interval;
+ ),
+ TP_printk(LOCAL_PR_FMT ", send beacons at interval: %d",
+ LOCAL_PR_ARG, __entry->interval)
+);
+
+DEFINE_EVENT(local_only_evt4, 802154_drv_exit_beacons_mode,
+ TP_PROTO(struct ieee802154_local *local),
+ TP_ARGS(local)
+);
+
#endif /* !__MAC802154_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--
2.27.0
When performing an active scan, coordinators emit beacon requests which
must be answered by other PANs receiving the request.
Answering a beacon request is considered a duty whenever the user
performs a "send beacons" command with an interval of 15. As in the
softMAC we save the interval in micro-seconds, we use a negative value
to discriminate between a passive beacons command and the task to answer
received beacon requests.
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/ieee802154_netdev.h | 4 +++-
net/ieee802154/header_ops.c | 13 +++++++++++++
net/mac802154/ieee802154_i.h | 17 ++++++++++++++++-
net/mac802154/rx.c | 13 +++++++++++++
net/mac802154/scan.c | 17 +++++++++++++----
5 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index 1bf1a4e508a2..a2dba4442c57 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -179,9 +179,11 @@ int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
*/
int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
-/* pushes a beacon_req or a beacon frame into an skb */
+/* pushes/pulls a beacon_req or a beacon frame into/from an skb */
int ieee802154_beacon_req_push(struct sk_buff *skb,
struct ieee802154_beacon_req_frame *breq);
+int ieee802154_beacon_req_pl_pull(struct sk_buff *skb,
+ struct ieee802154_mac_cmd_pl *mac_pl);
int ieee802154_beacon_push(struct sk_buff *skb,
struct ieee802154_beacon_frame *beacon);
diff --git a/net/ieee802154/header_ops.c b/net/ieee802154/header_ops.c
index c31a9e429a14..771dbcf6e0b8 100644
--- a/net/ieee802154/header_ops.c
+++ b/net/ieee802154/header_ops.c
@@ -314,6 +314,19 @@ ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
+int ieee802154_beacon_req_pl_pull(struct sk_buff *skb,
+ struct ieee802154_mac_cmd_pl *mac_pl)
+{
+ if (!pskb_may_pull(skb, sizeof(*mac_pl)))
+ return -EINVAL;
+
+ memcpy(mac_pl, skb->data, sizeof(*mac_pl));
+ skb_pull(skb, sizeof(*mac_pl));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ieee802154_beacon_req_pl_pull);
+
int
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 19c840500bd8..3d79c6ecbdf1 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -61,7 +61,7 @@ struct ieee802154_local {
/* Beacons handling */
bool ongoing_beacons_request;
struct mutex beacons_lock;
- unsigned int beacons_interval;
+ int beacons_interval;
struct delayed_work beacons_work;
struct ieee802154_sub_if_data __rcu *beacons_sdata;
struct ieee802154_beacon_frame beacon;
@@ -136,6 +136,21 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
return test_bit(SDATA_STATE_RUNNING, &sdata->state);
}
+static inline bool ieee802154_frame_is_beacon_req(struct sk_buff *skb)
+{
+ struct ieee802154_mac_cmd_pl mac_pl;
+ int ret;
+
+ if (mac_cb(skb)->type != IEEE802154_FC_TYPE_MAC_CMD)
+ return false;
+
+ ret = ieee802154_beacon_req_pl_pull(skb, &mac_pl);
+ if (ret)
+ return false;
+
+ return mac_pl.cmd_id == IEEE802154_CMD_BEACON_REQ;
+}
+
extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index f2f3eca9bc20..1aba23d007cf 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -29,6 +29,11 @@ static int ieee802154_deliver_skb(struct sk_buff *skb)
return netif_receive_skb(skb);
}
+static bool mac802154_should_answer_beacon_req(struct ieee802154_local *local)
+{
+ return local->ongoing_beacons_request && local->beacons_interval < 0;
+}
+
static int
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
struct sk_buff *skb, const struct ieee802154_hdr *hdr)
@@ -101,6 +106,14 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
}
goto fail;
case IEEE802154_FC_TYPE_MAC_CMD:
+ if (ieee802154_frame_is_beacon_req(skb) &&
+ mac802154_should_answer_beacon_req(sdata->local)) {
+ ieee802154_queue_delayed_work(&sdata->local->hw,
+ &sdata->local->beacons_work,
+ 0);
+ goto success;
+ }
+ goto fail;
case IEEE802154_FC_TYPE_ACK:
goto fail;
case IEEE802154_FC_TYPE_DATA:
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index a3ff65d5bb7a..c9412dfaeb66 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -142,7 +142,8 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
local->beacon.mhr.source.pan_id = cpu_to_le16(request->wpan_dev->pan_id);
local->beacon.mhr.source.extended_addr = cpu_to_le64(request->wpan_dev->extended_addr);
local->beacon.mac_pl.beacon_order = request->interval;
- local->beacon.mac_pl.superframe_order = request->interval;
+ if (request->interval <= IEEE802154_MAX_SCAN_DURATION)
+ local->beacon.mac_pl.superframe_order = request->interval;
local->beacon.mac_pl.final_cap_slot = 0xf;
local->beacon.mac_pl.battery_life_ext = 0;
local->beacon.mac_pl.pan_coordinator = 1;
@@ -150,6 +151,11 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
rcu_assign_pointer(local->beacons_sdata, sdata);
+ if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION) {
+ local->beacons_interval = -1;
+ return 0;
+ }
+
/* Start the beacon work */
local->beacons_interval =
mac802154_scan_get_channel_time(request->interval,
@@ -167,7 +173,9 @@ int mac802154_stop_beacons_locked(struct ieee802154_local *local)
return -ESRCH;
local->ongoing_beacons_request = false;
- cancel_delayed_work(&local->beacons_work);
+
+ if (local->beacons_interval >= 0)
+ cancel_delayed_work(&local->beacons_work);
return 0;
}
@@ -363,8 +371,9 @@ void mac802154_beacons_work(struct work_struct *work)
pr_err("Error when transmitting beacon (%d)\n", ret);
queue_work:
- ieee802154_queue_delayed_work(&local->hw, &local->beacons_work,
- local->beacons_interval);
+ if (local->beacons_interval >= 0)
+ ieee802154_queue_delayed_work(&local->hw, &local->beacons_work,
+ local->beacons_interval);
unlock_mutex:
mutex_unlock(&local->beacons_lock);
--
2.27.0
This involves processing beacons requests: starting or stopping
the flow of beacons sent passively on a specific interface. The page and
channel must be changed beforehands if needed. Interval orders above 14
are reserved to tell a device it must answer BEACON_REQ coming from an
active scan procedure (this is not supported yet).
A beacons request structure is created to list the requirements.
Mac layers may now implement the ->send_beacons() and
->stop_beacons() hooks.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/cfg802154.h | 22 +++++++++++
include/net/nl802154.h | 3 ++
net/ieee802154/nl802154.c | 81 +++++++++++++++++++++++++++++++++++++++
net/ieee802154/rdev-ops.h | 24 ++++++++++++
net/ieee802154/trace.h | 21 ++++++++++
5 files changed, 151 insertions(+)
diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
index 2118bfc02d7c..ab4d4b7461e6 100644
--- a/include/net/cfg802154.h
+++ b/include/net/cfg802154.h
@@ -88,6 +88,24 @@ struct cfg802154_scan_request {
struct wpan_phy *wpan_phy;
};
+/**
+ * struct cfg802154_beacons_request - beacons request descriptor
+ *
+ * @interval: interval n between sendings, in multiple order of the super frame
+ * duration: aBaseSuperframeDuration * (2^n) unless the interval
+ * order is greater or equal to 15, in this case beacons won't be
+ * passively sent out at a fixed rate but instead inform the device
+ * that it should answer beacon requests as part of active scan
+ * procedures
+ * @wpan_dev: the concerned wpan device
+ * @wpan_phy: the wpan phy this was for
+ */
+struct cfg802154_beacons_request {
+ u8 interval;
+ struct wpan_dev *wpan_dev;
+ struct wpan_phy *wpan_phy;
+};
+
struct cfg802154_ops {
struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy,
const char *name,
@@ -130,6 +148,10 @@ struct cfg802154_ops {
struct cfg802154_scan_request *request);
int (*abort_scan)(struct wpan_phy *wpan_phy,
struct wpan_dev *wpan_dev);
+ int (*send_beacons)(struct wpan_phy *wpan_phy,
+ struct cfg802154_beacons_request *request);
+ int (*stop_beacons)(struct wpan_phy *wpan_phy,
+ struct wpan_dev *wpan_dev);
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
void (*get_llsec_table)(struct wpan_phy *wpan_phy,
struct wpan_dev *wpan_dev,
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 22af514dd339..20c46f15cef4 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -65,6 +65,8 @@ enum nl802154_commands {
NL802154_CMD_FLUSH_PANS,
NL802154_CMD_SET_MAX_PAN_ENTRIES,
NL802154_CMD_SET_PANS_EXPIRATION,
+ NL802154_CMD_SEND_BEACONS,
+ NL802154_CMD_STOP_BEACONS,
/* add new commands above here */
@@ -148,6 +150,7 @@ enum nl802154_attrs {
NL802154_ATTR_PAN,
NL802154_ATTR_MAX_PAN_ENTRIES,
NL802154_ATTR_PANS_EXPIRATION,
+ NL802154_ATTR_BEACON_INTERVAL,
/* add attributes here, update the policy in nl802154.c */
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 62591ba7ed44..a5dcc69f0899 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -226,6 +226,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
[NL802154_ATTR_PAN] = { .type = NLA_NESTED },
[NL802154_ATTR_MAX_PAN_ENTRIES] = { .type = NLA_U32 },
[NL802154_ATTR_PANS_EXPIRATION] = { .type = NLA_U32 },
+ [NL802154_ATTR_BEACON_INTERVAL] = { .type = NLA_U8 },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
@@ -1686,6 +1687,70 @@ static int nl802154_set_pans_expiration(struct sk_buff *skb,
return 0;
}
+static int
+nl802154_send_beacons(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+ struct wpan_phy *wpan_phy = &rdev->wpan_phy;
+ struct cfg802154_beacons_request *request;
+ int err;
+
+ /* Avoid sending beacons on monitor interfaces */
+ if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
+ return -EOPNOTSUPP;
+
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ request->wpan_dev = wpan_dev;
+ request->wpan_phy = wpan_phy;
+
+ if (info->attrs[NL802154_ATTR_BEACON_INTERVAL]) {
+ request->interval = nla_get_u8(info->attrs[NL802154_ATTR_BEACON_INTERVAL]);
+ if (request->interval > IEEE802154_ACTIVE_SCAN_DURATION) {
+ pr_err("Interval is out of range\n");
+ err = -EINVAL;
+ goto free_request;
+ }
+ } else {
+ /* Use maximum duration order by default */
+ request->interval = IEEE802154_MAX_SCAN_DURATION;
+ }
+
+ err = rdev_send_beacons(rdev, request);
+ if (err) {
+ pr_err("Failure starting sending beacons (%d)\n", err);
+ goto free_request;
+ }
+
+ if (wpan_dev->netdev)
+ dev_hold(wpan_dev->netdev);
+
+free_request:
+ kfree(request);
+
+ return err;
+}
+
+static int
+nl802154_stop_beacons(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
+ int err;
+
+ err = rdev_stop_beacons(rdev, wpan_dev);
+
+ if (err != -ESRCH && wpan_dev->netdev)
+ dev_put(wpan_dev->netdev);
+
+ return err;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2816,6 +2881,22 @@ static const struct genl_ops nl802154_ops[] = {
.internal_flags = NL802154_FLAG_NEED_NETDEV |
NL802154_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL802154_CMD_SEND_BEACONS,
+ .doit = nl802154_send_beacons,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_CHECK_NETDEV_UP |
+ NL802154_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL802154_CMD_STOP_BEACONS,
+ .doit = nl802154_stop_beacons,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_CHECK_NETDEV_UP |
+ NL802154_FLAG_NEED_RTNL,
+ },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
{
.cmd = NL802154_CMD_SET_SEC_PARAMS,
diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h
index e171d74c3251..fa85efeaa150 100644
--- a/net/ieee802154/rdev-ops.h
+++ b/net/ieee802154/rdev-ops.h
@@ -237,6 +237,30 @@ static inline int rdev_abort_scan(struct cfg802154_registered_device *rdev,
return ret;
}
+static inline int rdev_send_beacons(struct cfg802154_registered_device *rdev,
+ struct cfg802154_beacons_request *request)
+{
+ int ret;
+
+ /* TODO: check if this is an FFD? */
+
+ trace_802154_rdev_send_beacons(&rdev->wpan_phy, request);
+ ret = rdev->ops->send_beacons(&rdev->wpan_phy, request);
+ trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+ return ret;
+}
+
+static inline int rdev_stop_beacons(struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev)
+{
+ int ret;
+
+ trace_802154_rdev_stop_beacons(&rdev->wpan_phy, wpan_dev);
+ ret = rdev->ops->stop_beacons(&rdev->wpan_phy, wpan_dev);
+ trace_802154_rdev_return_int(&rdev->wpan_phy, ret);
+ return ret;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
/* TODO this is already a nl802154, so move into ieee802154 */
static inline void
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
index e5405f737ded..353ba799244f 100644
--- a/net/ieee802154/trace.h
+++ b/net/ieee802154/trace.h
@@ -315,6 +315,22 @@ TRACE_EVENT(802154_rdev_trigger_scan,
WPAN_PHY_PR_ARG, __entry->page, __entry->channels, __entry->duration)
);
+TRACE_EVENT(802154_rdev_send_beacons,
+ TP_PROTO(struct wpan_phy *wpan_phy,
+ struct cfg802154_beacons_request *request),
+ TP_ARGS(wpan_phy, request),
+ TP_STRUCT__entry(
+ WPAN_PHY_ENTRY
+ __field(u8, interval)
+ ),
+ TP_fast_assign(
+ WPAN_PHY_ASSIGN;
+ __entry->interval = request->interval;
+ ),
+ TP_printk(WPAN_PHY_PR_FMT ", sending beacons (interval order: %d)",
+ WPAN_PHY_PR_ARG, __entry->interval)
+);
+
DECLARE_EVENT_CLASS(802154_wdev_template,
TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev),
TP_ARGS(wpan_phy, wpan_dev),
@@ -335,6 +351,11 @@ DEFINE_EVENT(802154_wdev_template, 802154_rdev_abort_scan,
TP_ARGS(wpan_phy, wpan_dev)
);
+DEFINE_EVENT(802154_wdev_template, 802154_rdev_stop_beacons,
+ TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev),
+ TP_ARGS(wpan_phy, wpan_dev)
+);
+
TRACE_EVENT(802154_rdev_return_int,
TP_PROTO(struct wpan_phy *wpan_phy, int ret),
TP_ARGS(wpan_phy, ret),
--
2.27.0
Now that scanning is supported and PANs properly registered, give
certain rights to the user, such as listing asynchronously the listed
PANs as well as flushing the list.
The maximum number of PANs to list and their delay before expiration can
be configured. By default there is no limit. When these parameters are
set, PANs are automatically dropped from the list.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/net/nl802154.h | 47 +++++++++
net/ieee802154/nl802154.c | 195 ++++++++++++++++++++++++++++++++++++++
2 files changed, 242 insertions(+)
diff --git a/include/net/nl802154.h b/include/net/nl802154.h
index 51eca3a2b14e..22af514dd339 100644
--- a/include/net/nl802154.h
+++ b/include/net/nl802154.h
@@ -61,6 +61,10 @@ enum nl802154_commands {
NL802154_CMD_TRIGGER_SCAN,
NL802154_CMD_ABORT_SCAN,
NL802154_CMD_SCAN_DONE,
+ NL802154_CMD_DUMP_PANS,
+ NL802154_CMD_FLUSH_PANS,
+ NL802154_CMD_SET_MAX_PAN_ENTRIES,
+ NL802154_CMD_SET_PANS_EXPIRATION,
/* add new commands above here */
@@ -141,6 +145,9 @@ enum nl802154_attrs {
NL802154_ATTR_SCAN_FLAGS,
NL802154_ATTR_SCAN_CHANNELS,
NL802154_ATTR_SCAN_DURATION,
+ NL802154_ATTR_PAN,
+ NL802154_ATTR_MAX_PAN_ENTRIES,
+ NL802154_ATTR_PANS_EXPIRATION,
/* add attributes here, update the policy in nl802154.c */
@@ -267,6 +274,46 @@ enum nl802154_scan_flags {
NL802154_SCAN_FLAG_RANDOM_ADDR = BIT(0),
};
+/**
+ * enum nl802154_pan - Netlink attributes for a PAN
+ *
+ * @__NL802154_PAN_INVALID: invalid
+ * @NL802154_PAN_PANID: PANID of the PAN (2 bytes)
+ * @NL802154_PAN_COORD_ADDR: Coordinator address, (8 bytes or 2 bytes)
+ * @NL802154_PAN_CHANNEL: channel number, related to @NL802154_PAN_PAGE (u8)
+ * @NL802154_PAN_PAGE: channel page, related to @NL802154_PAN_CHANNEL (u8)
+ * @NL802154_PAN_PREAMBLE_CODE: Preamble code while the beacon was received,
+ * this is PHY dependent and optional (4 bytes)
+ * @NL802154_PAN_SUPERFRAME_SPEC: superframe specification of the PAN (u16)
+ * @NL802154_PAN_LINK_QUALITY: signal quality of beacon in unspecified units,
+ * scaled to 0..255 (u8)
+ * @NL802154_PAN_GTS_PERMIT: set to true if GTS is permitted on this PAN
+ * @NL802154_PAN_PAYLOAD_DATA: binary data containing the raw data from the
+ * frame payload, (only if beacon or probe response had data)
+ * @NL802154_PAN_STATUS: status, if this PAN is "used"
+ * @NL802154_PAN_SEEN_MS_AGO: age of this PAN entry in ms
+ * @NL802154_PAN_PAD: attribute used for padding for 64-bit alignment
+ * @NL802154_PAN_MAX: highest PAN attribute
+ */
+enum nl802154_pan {
+ __NL802154_PAN_INVALID,
+ NL802154_PAN_PANID,
+ NL802154_PAN_COORD_ADDR,
+ NL802154_PAN_CHANNEL,
+ NL802154_PAN_PAGE,
+ NL802154_PAN_PREAMBLE_CODE,
+ NL802154_PAN_SUPERFRAME_SPEC,
+ NL802154_PAN_LINK_QUALITY,
+ NL802154_PAN_GTS_PERMIT,
+ NL802154_PAN_PAYLOAD_DATA,
+ NL802154_PAN_STATUS,
+ NL802154_PAN_SEEN_MS_AGO,
+ NL802154_PAN_PAD,
+
+ /* keep last */
+ NL802154_PAN_MAX,
+};
+
/**
* enum nl802154_cca_modes - cca modes
*
diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c
index 99cbad1f1381..62591ba7ed44 100644
--- a/net/ieee802154/nl802154.c
+++ b/net/ieee802154/nl802154.c
@@ -223,6 +223,9 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
[NL802154_ATTR_SCAN_FLAGS] = { .type = NLA_U32 },
[NL802154_ATTR_SCAN_CHANNELS] = { .type = NLA_U32 },
[NL802154_ATTR_SCAN_DURATION] = { .type = NLA_U8 },
+ [NL802154_ATTR_PAN] = { .type = NLA_NESTED },
+ [NL802154_ATTR_MAX_PAN_ENTRIES] = { .type = NLA_U32 },
+ [NL802154_ATTR_PANS_EXPIRATION] = { .type = NLA_U32 },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
[NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, },
@@ -1517,6 +1520,172 @@ static int nl802154_abort_scan(struct sk_buff *skb, struct genl_info *info)
return rdev_abort_scan(rdev, wpan_dev);
}
+static int nl802154_send_pan_info(struct sk_buff *msg,
+ struct netlink_callback *cb,
+ u32 seq, int flags,
+ struct cfg802154_registered_device *rdev,
+ struct wpan_dev *wpan_dev,
+ struct cfg802154_internal_pan *intpan)
+{
+ struct ieee802154_pan_desc *pan = &intpan->desc;
+ struct nlattr *nla;
+ void *hdr;
+
+ ASSERT_RTNL();
+
+ hdr = nl802154hdr_put(msg, NETLINK_CB(cb->skb).portid, seq, flags,
+ NL802154_CMD_SCAN_DONE);
+ if (!hdr)
+ return -ENOBUFS;
+
+ genl_dump_check_consistent(cb, hdr);
+
+ if (nla_put_u32(msg, NL802154_ATTR_GENERATION, rdev->pan_generation))
+ goto nla_put_failure;
+
+ if (wpan_dev->netdev &&
+ nla_put_u32(msg, NL802154_ATTR_IFINDEX, wpan_dev->netdev->ifindex))
+ goto nla_put_failure;
+
+ if (nla_put_u64_64bit(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev),
+ NL802154_ATTR_PAD))
+ goto nla_put_failure;
+
+ nla = nla_nest_start_noflag(msg, NL802154_ATTR_PAN);
+ if (!nla)
+ goto nla_put_failure;
+
+ if (nla_put(msg, NL802154_PAN_PANID, IEEE802154_PAN_ID_LEN,
+ &pan->coord->pan_id))
+ goto nla_put_failure;
+
+ if (pan->coord->mode == IEEE802154_ADDR_SHORT) {
+ if (nla_put(msg, NL802154_PAN_COORD_ADDR,
+ IEEE802154_SHORT_ADDR_LEN,
+ &pan->coord->short_addr))
+ goto nla_put_failure;
+ } else {
+ if (nla_put(msg, NL802154_PAN_COORD_ADDR,
+ IEEE802154_EXTENDED_ADDR_LEN,
+ &pan->coord->extended_addr))
+ goto nla_put_failure;
+ }
+
+ if (nla_put_u8(msg, NL802154_PAN_CHANNEL, pan->channel))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, NL802154_PAN_PAGE, pan->page))
+ goto nla_put_failure;
+
+ if (nla_put_u16(msg, NL802154_PAN_SUPERFRAME_SPEC,
+ pan->superframe_spec))
+ goto nla_put_failure;
+
+ if (nla_put_u8(msg, NL802154_PAN_LINK_QUALITY, pan->link_quality))
+ goto nla_put_failure;
+
+ if (nla_put_u32(msg, NL802154_PAN_SEEN_MS_AGO,
+ jiffies_to_msecs(jiffies - intpan->discovery_ts)))
+ goto nla_put_failure;
+
+ if (pan->gts_permit && nla_put_flag(msg, NL802154_PAN_GTS_PERMIT))
+ goto nla_put_failure;
+
+ /* TODO: NL802154_PAN_PAYLOAD_DATA if any */
+
+ nla_nest_end(msg, nla);
+ genlmsg_end(msg, hdr);
+
+ return 0;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
+static int nl802154_dump_pans(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct cfg802154_registered_device *rdev;
+ struct cfg802154_internal_pan *pan;
+ struct wpan_dev *wpan_dev;
+ int err;
+
+ err = nl802154_prepare_wpan_dev_dump(skb, cb, &rdev, &wpan_dev);
+ if (err)
+ return err;
+
+ spin_lock_bh(&rdev->pan_lock);
+
+ if (cb->args[2])
+ goto out;
+
+ cb->seq = rdev->pan_generation;
+
+ ieee802154_for_each_pan(pan, rdev) {
+ err = nl802154_send_pan_info(skb, cb, cb->nlh->nlmsg_seq,
+ NLM_F_MULTI, rdev, wpan_dev, pan);
+ if (err < 0)
+ goto out_err;
+ }
+
+ cb->args[2] = 1;
+out:
+ err = skb->len;
+out_err:
+ spin_unlock_bh(&rdev->pan_lock);
+
+ nl802154_finish_wpan_dev_dump(rdev);
+
+ return err;
+}
+
+static int nl802154_flush_pans(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+
+ spin_lock_bh(&rdev->pan_lock);
+ cfg802154_flush_pans(rdev);
+ spin_unlock_bh(&rdev->pan_lock);
+
+ return 0;
+}
+
+static int nl802154_set_max_pan_entries(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ unsigned int max_entries;
+
+ if (!info->attrs[NL802154_ATTR_MAX_PAN_ENTRIES])
+ return -EINVAL;
+
+ max_entries = nla_get_u32(info->attrs[NL802154_ATTR_MAX_PAN_ENTRIES]);
+
+ spin_lock_bh(&rdev->pan_lock);
+ cfg802154_set_max_pan_entries(rdev, max_entries);
+ spin_unlock_bh(&rdev->pan_lock);
+
+ return 0;
+}
+
+static int nl802154_set_pans_expiration(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg802154_registered_device *rdev = info->user_ptr[0];
+ unsigned int exp_time_s;
+
+ if (!info->attrs[NL802154_ATTR_PANS_EXPIRATION])
+ return -EINVAL;
+
+ exp_time_s = nla_get_u32(info->attrs[NL802154_ATTR_PANS_EXPIRATION]);
+
+ spin_lock_bh(&rdev->pan_lock);
+ cfg802154_set_pans_expiration(rdev, exp_time_s);
+ spin_unlock_bh(&rdev->pan_lock);
+
+ return 0;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = {
[NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 },
@@ -2621,6 +2790,32 @@ static const struct genl_ops nl802154_ops[] = {
NL802154_FLAG_CHECK_NETDEV_UP |
NL802154_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL802154_CMD_DUMP_PANS,
+ .dumpit = nl802154_dump_pans,
+ /* can be retrieved by unprivileged users */
+ },
+ {
+ .cmd = NL802154_CMD_FLUSH_PANS,
+ .doit = nl802154_flush_pans,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL802154_CMD_SET_MAX_PAN_ENTRIES,
+ .doit = nl802154_set_max_pan_entries,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL802154_CMD_SET_PANS_EXPIRATION,
+ .doit = nl802154_set_pans_expiration,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL802154_FLAG_NEED_NETDEV |
+ NL802154_FLAG_NEED_RTNL,
+ },
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
{
.cmd = NL802154_CMD_SET_SEC_PARAMS,
--
2.27.0
From: David Girault <[email protected]>
Add an internal trace when new PANs get discovered.
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
net/ieee802154/pan.c | 3 +++
net/ieee802154/trace.h | 25 +++++++++++++++++++++++++
2 files changed, 28 insertions(+)
diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c
index 1ea15ea1b3bd..5afc0aa38a43 100644
--- a/net/ieee802154/pan.c
+++ b/net/ieee802154/pan.c
@@ -18,6 +18,7 @@
#include "ieee802154.h"
#include "core.h"
+#include "trace.h"
static struct cfg802154_internal_pan *
cfg802154_alloc_pan(struct ieee802154_pan_desc *desc)
@@ -205,6 +206,8 @@ static void cfg802154_pan_update(struct cfg802154_registered_device *rdev,
found = cfg802154_find_matching_pan(rdev, new);
if (found)
cfg802154_unlink_pan(rdev, found);
+ else
+ trace_802154_new_pan(&new->desc);
if (unlikely(cfg802154_need_to_expire_pans(rdev)))
cfg802154_expire_oldest_pan(rdev);
diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h
index 353ba799244f..506fe4930440 100644
--- a/net/ieee802154/trace.h
+++ b/net/ieee802154/trace.h
@@ -356,6 +356,31 @@ DEFINE_EVENT(802154_wdev_template, 802154_rdev_stop_beacons,
TP_ARGS(wpan_phy, wpan_dev)
);
+DECLARE_EVENT_CLASS(802154_pan_evt,
+ TP_PROTO(struct ieee802154_pan_desc *desc),
+ TP_ARGS(desc),
+ TP_STRUCT__entry(
+ __field(u16, pan_id)
+ __field(__le64, coord_addr)
+ __field(u8, channel)
+ __field(u8, page)
+ ),
+ TP_fast_assign(
+ __entry->page = desc->page;
+ __entry->channel = desc->channel;
+ memcpy(&__entry->pan_id, &desc->coord->pan_id, 2);
+ memcpy(&__entry->coord_addr, &desc->coord->extended_addr, 8);
+ ),
+ TP_printk("panid: %u, coord_addr: 0x%llx, page: %u, channel: %u",
+ __entry->pan_id, __le64_to_cpu(__entry->coord_addr),
+ __entry->page, __entry->channel)
+);
+
+DEFINE_EVENT(802154_pan_evt, 802154_new_pan,
+ TP_PROTO(struct ieee802154_pan_desc *desc),
+ TP_ARGS(desc)
+);
+
TRACE_EVENT(802154_rdev_return_int,
TP_PROTO(struct wpan_phy *wpan_phy, int ret),
TP_ARGS(wpan_phy, ret),
--
2.27.0
The Cascada 8210 hardware transceiver is kind of a hardMAC which
interfaces with the softMAC and in practice does not support sending
anything else than dataframes. This means we cannot send any BEACON_REQ
during active scans nor any BEACON in general. Refuse these operations
officially so that the user is aware of the limitation.
Signed-off-by: Miquel Raynal <[email protected]>
---
drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
index d3a9e4fe05f4..49c274280e3c 100644
--- a/drivers/net/ieee802154/ca8210.c
+++ b/drivers/net/ieee802154/ca8210.c
@@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
return link_to_linux_err(status);
}
+static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
+ struct cfg802154_scan_request *request)
+{
+ /* This xceiver can only send dataframes */
+ if (request->type != NL802154_SCAN_PASSIVE)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
+ struct cfg802154_beacons_request *request)
+{
+ /* This xceiver can only send dataframes */
+ return -EOPNOTSUPP;
+}
+
+static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
+
static const struct ieee802154_ops ca8210_phy_ops = {
.start = ca8210_start,
.stop = ca8210_stop,
@@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
.set_cca_ed_level = ca8210_set_cca_ed_level,
.set_csma_params = ca8210_set_csma_params,
.set_frame_retries = ca8210_set_frame_retries,
- .set_promiscuous_mode = ca8210_set_promiscuous_mode
+ .set_promiscuous_mode = ca8210_set_promiscuous_mode,
+ .enter_scan_mode = ca8210_enter_scan_mode,
+ .exit_scan_mode = ca8210_exit_scan_beacons_mode,
+ .enter_beacons_mode = ca8210_enter_beacons_mode,
+ .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
};
/* Test/EVBME Interface */
--
2.27.0
Implement the core hooks in order to provide the softMAC layer support
for scan requests and aborts.
Changing the channels is prohibited during the scan.
As transceiver enter in a promiscuous mode during scans, they might stop
checking frame validity so we ensure this gets done at mac level.
The implementation uses a workqueue triggered at a certain interval
depending on the symbol duration for the current channel and the
duration order provided.
Received beacons during a passive scanning procedure are processed and
either registered in the list of known PANs or the existing entry gets
updated accordingly.
Active scanning is not supported yet.
Co-developed-by: David Girault <[email protected]>
Signed-off-by: David Girault <[email protected]>
Signed-off-by: Miquel Raynal <[email protected]>
---
include/linux/ieee802154.h | 4 +
include/net/mac802154.h | 14 ++
net/mac802154/Makefile | 2 +-
net/mac802154/cfg.c | 39 ++++++
net/mac802154/ieee802154_i.h | 22 +++
net/mac802154/main.c | 2 +
net/mac802154/rx.c | 21 ++-
net/mac802154/scan.c | 255 +++++++++++++++++++++++++++++++++++
net/mac802154/tx.c | 3 +
net/mac802154/util.c | 26 ++++
10 files changed, 382 insertions(+), 6 deletions(-)
create mode 100644 net/mac802154/scan.c
diff --git a/include/linux/ieee802154.h b/include/linux/ieee802154.h
index 41178c87c43c..57bf5317338e 100644
--- a/include/linux/ieee802154.h
+++ b/include/linux/ieee802154.h
@@ -47,6 +47,10 @@
/* Duration in superframe order */
#define IEEE802154_MAX_SCAN_DURATION 14
#define IEEE802154_ACTIVE_SCAN_DURATION 15
+/* Superframe duration in slots */
+#define IEEE802154_SUPERFRAME_PERIOD 16
+/* Various periods expressed in symbols */
+#define IEEE802154_SLOT_PERIOD 60
#define IEEE802154_LIFS_PERIOD 40
#define IEEE802154_SIFS_PERIOD 12
#define IEEE802154_MAX_SIFS_FRAME_SIZE 18
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index d524ffb9eb25..19bfbf591ea1 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -486,4 +486,18 @@ void ieee802154_stop_queue(struct ieee802154_hw *hw);
void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb,
bool ifs_handling);
+/**
+ * ieee802154_queue_delayed_work - add work onto the mac802154 workqueue
+ *
+ * Drivers and mac802154 use this to queue delayed work onto the mac802154
+ * workqueue.
+ *
+ * @hw: the hardware struct for the interface we are adding work for
+ * @dwork: delayable work to queue onto the mac802154 workqueue
+ * @delay: number of jiffies to wait before queueing
+ */
+void ieee802154_queue_delayed_work(struct ieee802154_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay);
+
#endif /* NET_MAC802154_H */
diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile
index 4059295fdbf8..43d1347b37ee 100644
--- a/net/mac802154/Makefile
+++ b/net/mac802154/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MAC802154) += mac802154.o
mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \
- iface.o llsec.o util.o cfg.o trace.o
+ iface.o llsec.o util.o cfg.o scan.o trace.o
CFLAGS_trace.o := -I$(src)
diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
index ba57da07c08e..c1e7bbea3058 100644
--- a/net/mac802154/cfg.c
+++ b/net/mac802154/cfg.c
@@ -109,6 +109,10 @@ int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
ASSERT_RTNL();
+ /* Refuse to change channels during a scanning operation */
+ if (mac802154_scan_is_ongoing(local))
+ return -EBUSY;
+
ret = drv_set_channel(local, page, channel);
if (!ret) {
wpan_phy->current_page = page;
@@ -268,6 +272,39 @@ ieee802154_set_ackreq_default(struct wpan_phy *wpan_phy,
return 0;
}
+static int mac802154_trigger_scan(struct wpan_phy *wpan_phy,
+ struct cfg802154_scan_request *req)
+{
+ struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+ struct ieee802154_sub_if_data *sdata;
+ int ret;
+
+ sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(req->wpan_dev);
+
+ ASSERT_RTNL();
+
+ mutex_lock(&local->scan_lock);
+ ret = mac802154_trigger_scan_locked(sdata, req);
+ mutex_unlock(&local->scan_lock);
+
+ return ret;
+}
+
+static int mac802154_abort_scan(struct wpan_phy *wpan_phy,
+ struct wpan_dev *wpan_dev)
+{
+ struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
+ int ret;
+
+ ASSERT_RTNL();
+
+ mutex_lock(&local->scan_lock);
+ ret = mac802154_abort_scan_locked(local);
+ mutex_unlock(&local->scan_lock);
+
+ return ret;
+}
+
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static void
ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
@@ -475,6 +512,8 @@ const struct cfg802154_ops mac802154_config_ops = {
.set_max_frame_retries = ieee802154_set_max_frame_retries,
.set_lbt_mode = ieee802154_set_lbt_mode,
.set_ackreq_default = ieee802154_set_ackreq_default,
+ .trigger_scan = mac802154_trigger_scan,
+ .abort_scan = mac802154_abort_scan,
#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
.get_llsec_table = ieee802154_get_llsec_table,
.lock_llsec_table = ieee802154_lock_llsec_table,
diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h
index 8a7f4c83c5b6..5cc3ac8fd4a1 100644
--- a/net/mac802154/ieee802154_i.h
+++ b/net/mac802154/ieee802154_i.h
@@ -48,6 +48,15 @@ struct ieee802154_local {
struct hrtimer ifs_timer;
+ /* Scanning */
+ struct mutex scan_lock;
+ atomic_t scanning;
+ __le64 scan_addr;
+ int scan_channel_idx;
+ struct cfg802154_scan_request __rcu *scan_req;
+ struct ieee802154_sub_if_data __rcu *scan_sdata;
+ struct delayed_work scan_work;
+
bool started;
bool suspended;
@@ -167,6 +176,19 @@ void mac802154_unlock_table(struct net_device *dev);
int mac802154_wpan_update_llsec(struct net_device *dev);
+/* scanning handling */
+void mac802154_scan_work(struct work_struct *work);
+int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
+ struct cfg802154_scan_request *request);
+int mac802154_abort_scan_locked(struct ieee802154_local *local);
+int mac802154_scan_process_beacon(struct ieee802154_local *local,
+ struct sk_buff *skb);
+
+static inline bool mac802154_scan_is_ongoing(struct ieee802154_local *local)
+{
+ return atomic_read(&local->scanning);
+}
+
/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
diff --git a/net/mac802154/main.c b/net/mac802154/main.c
index 88826c5aa4ba..09e2fc6848cb 100644
--- a/net/mac802154/main.c
+++ b/net/mac802154/main.c
@@ -90,12 +90,14 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
INIT_LIST_HEAD(&local->interfaces);
mutex_init(&local->iflist_mtx);
+ mutex_init(&local->scan_lock);
tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
skb_queue_head_init(&local->skb_queue);
INIT_WORK(&local->tx_work, ieee802154_xmit_worker);
+ INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_work);
/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c
index b8ce84618a55..f2f3eca9bc20 100644
--- a/net/mac802154/rx.c
+++ b/net/mac802154/rx.c
@@ -94,10 +94,15 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
switch (mac_cb(skb)->type) {
case IEEE802154_FC_TYPE_BEACON:
- case IEEE802154_FC_TYPE_ACK:
+ if (mac802154_scan_is_ongoing(sdata->local)) {
+ rc = mac802154_scan_process_beacon(sdata->local, skb);
+ if (!rc)
+ goto success;
+ }
+ goto fail;
case IEEE802154_FC_TYPE_MAC_CMD:
+ case IEEE802154_FC_TYPE_ACK:
goto fail;
-
case IEEE802154_FC_TYPE_DATA:
return ieee802154_deliver_skb(skb);
default:
@@ -109,6 +114,10 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
fail:
kfree_skb(skb);
return NET_RX_DROP;
+
+success:
+ kfree_skb(skb);
+ return NET_RX_SUCCESS;
}
static void
@@ -268,10 +277,12 @@ void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb)
ieee802154_monitors_rx(local, skb);
- /* Check if transceiver doesn't validate the checksum.
- * If not we validate the checksum here.
+ /* Check if the transceiver doesn't validate the checksum, or if the
+ * check might have been disabled like during a scan. In these cases,
+ * we validate the checksum here.
*/
- if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM) {
+ if (local->hw.flags & IEEE802154_HW_RX_DROP_BAD_CKSUM ||
+ mac802154_scan_is_ongoing(local)) {
crc = crc_ccitt(0, skb->data, skb->len);
if (crc) {
rcu_read_unlock();
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
new file mode 100644
index 000000000000..7be63d73caa9
--- /dev/null
+++ b/net/mac802154/scan.c
@@ -0,0 +1,255 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * IEEE 802.15.4 scanning management
+ *
+ * Copyright (C) Qorvo, 2021
+ * Authors:
+ * - David Girault <[email protected]>
+ * - Miquel Raynal <[email protected]>
+ */
+
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/rtnetlink.h>
+#include <net/mac802154.h>
+
+#include "ieee802154_i.h"
+#include "driver-ops.h"
+#include "../ieee802154/nl802154.h"
+
+static bool mac802154_check_promiscuous(struct ieee802154_local *local)
+{
+ struct ieee802154_sub_if_data *sdata;
+ bool promiscuous_on = false;
+
+ /* Check if one subif is already in promiscuous mode. Since the list is
+ * protected by its own mutex, take it here to ensure no modification
+ * occurs during the check.
+ */
+ mutex_lock(&local->iflist_mtx);
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (ieee802154_sdata_running(sdata) &&
+ sdata->wpan_dev.promiscuous_mode) {
+ /* At least one is in promiscuous mode */
+ promiscuous_on = true;
+ break;
+ }
+ }
+ mutex_unlock(&local->iflist_mtx);
+ return promiscuous_on;
+}
+
+static int mac802154_set_promiscuous_mode(struct ieee802154_local *local,
+ bool state)
+{
+ bool promiscuous_on = mac802154_check_promiscuous(local);
+ int ret;
+
+ if ((state && promiscuous_on) || (!state && !promiscuous_on))
+ return 0;
+
+ ret = drv_set_promiscuous_mode(local, state);
+ if (ret)
+ pr_err("Failed to %s promiscuous mode for SW scanning",
+ state ? "set" : "reset");
+
+ return ret;
+}
+
+static int mac802154_send_scan_done(struct ieee802154_local *local)
+{
+ struct cfg802154_registered_device *rdev;
+ struct cfg802154_scan_request *scan_req;
+ struct wpan_dev *wpan_dev;
+
+ scan_req = rcu_dereference_protected(local->scan_req,
+ lockdep_is_held(&local->scan_lock));
+ rdev = wpan_phy_to_rdev(scan_req->wpan_phy);
+ wpan_dev = scan_req->wpan_dev;
+
+ return nl802154_send_scan_done(rdev, wpan_dev);
+}
+
+static int mac802154_end_of_scan(struct ieee802154_local *local)
+{
+ drv_set_channel(local, local->phy->current_page,
+ local->phy->current_channel);
+ ieee802154_set_symbol_duration(local->phy);
+ atomic_set(&local->scanning, 0);
+ mac802154_set_promiscuous_mode(local, false);
+ ieee802154_wake_queue(&local->hw);
+
+ return mac802154_send_scan_done(local);
+}
+
+int mac802154_abort_scan_locked(struct ieee802154_local *local)
+{
+ lockdep_assert_held(&local->scan_lock);
+
+ if (!mac802154_scan_is_ongoing(local))
+ return -ESRCH;
+
+ cancel_delayed_work(&local->scan_work);
+
+ return mac802154_end_of_scan(local);
+}
+
+static unsigned int mac802154_scan_get_channel_time(u8 duration_order,
+ u8 symbol_duration)
+{
+ u64 base_super_frame_duration = (u64)symbol_duration *
+ IEEE802154_SUPERFRAME_PERIOD * IEEE802154_SLOT_PERIOD;
+
+ return usecs_to_jiffies(base_super_frame_duration *
+ (BIT(duration_order) + 1));
+}
+
+void mac802154_scan_work(struct work_struct *work)
+{
+ struct ieee802154_local *local =
+ container_of(work, struct ieee802154_local, scan_work.work);
+ struct cfg802154_scan_request *scan_req;
+ struct ieee802154_sub_if_data *sdata;
+ unsigned int scan_duration;
+ bool end_of_scan = false;
+ unsigned long chan;
+ int ret;
+
+ mutex_lock(&local->scan_lock);
+
+ if (!mac802154_scan_is_ongoing(local))
+ goto unlock_mutex;
+
+ sdata = rcu_dereference_protected(local->scan_sdata,
+ lockdep_is_held(&local->scan_lock));
+ scan_req = rcu_dereference_protected(local->scan_req,
+ lockdep_is_held(&local->scan_lock));
+
+ if (local->suspended || !ieee802154_sdata_running(sdata))
+ goto queue_work;
+
+ do {
+ chan = find_next_bit((const unsigned long *)&scan_req->channels,
+ IEEE802154_MAX_CHANNEL + 1,
+ local->scan_channel_idx + 1);
+
+ /* If there are no more channels left, complete the scan */
+ if (chan > IEEE802154_MAX_CHANNEL) {
+ end_of_scan = true;
+ goto unlock_mutex;
+ }
+
+ /* Channel switch cannot be made atomic so hide the chan number
+ * in order to prevent beacon processing during this timeframe.
+ */
+ local->scan_channel_idx = -1;
+ /* Bypass the stack on purpose */
+ ret = drv_set_channel(local, scan_req->page, chan);
+ local->scan_channel_idx = chan;
+ ieee802154_set_symbol_duration(local->phy);
+ } while (ret);
+
+queue_work:
+ scan_duration = mac802154_scan_get_channel_time(scan_req->duration,
+ local->phy->symbol_duration);
+ pr_debug("Scan channel %lu of page %u for %ums\n",
+ chan, scan_req->page, jiffies_to_msecs(scan_duration));
+ ieee802154_queue_delayed_work(&local->hw, &local->scan_work,
+ scan_duration);
+
+unlock_mutex:
+ if (end_of_scan)
+ mac802154_end_of_scan(local);
+
+ mutex_unlock(&local->scan_lock);
+}
+
+int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
+ struct cfg802154_scan_request *request)
+{
+ struct ieee802154_local *local = sdata->local;
+ int ret;
+
+ lockdep_assert_held(&local->scan_lock);
+
+ if (mac802154_scan_is_ongoing(local))
+ return -EBUSY;
+
+ /* TODO: support other scanning type */
+ if (request->type != NL802154_SCAN_PASSIVE)
+ return -EOPNOTSUPP;
+
+ /* Store scanning parameters */
+ rcu_assign_pointer(local->scan_req, request);
+ rcu_assign_pointer(local->scan_sdata, sdata);
+
+ /* Configure scan_addr to use net_device addr or random */
+ if (request->flags & NL802154_SCAN_FLAG_RANDOM_ADDR)
+ get_random_bytes(&local->scan_addr, sizeof(local->scan_addr));
+ else
+ local->scan_addr = cpu_to_le64(get_unaligned_be64(sdata->dev->dev_addr));
+
+ local->scan_channel_idx = -1;
+ atomic_set(&local->scanning, 1);
+
+ /* Software scanning requires to set promiscuous mode, so we need to
+ * pause the Tx queue
+ */
+ ieee802154_stop_queue(&local->hw);
+ ret = mac802154_set_promiscuous_mode(local, true);
+ if (ret)
+ return mac802154_end_of_scan(local);
+
+ ieee802154_queue_delayed_work(&local->hw, &local->scan_work, 0);
+
+ return 0;
+}
+
+int mac802154_scan_process_beacon(struct ieee802154_local *local,
+ struct sk_buff *skb)
+{
+ struct ieee802154_beacon_hdr *bh = (void *)skb->data;
+ struct ieee802154_addr *src = &mac_cb(skb)->source;
+ struct cfg802154_scan_request *scan_req;
+ struct ieee802154_pan_desc desc = {};
+ int ret;
+
+ /* Check the validity of the frame length */
+ if (skb->len < sizeof(*bh))
+ return -EINVAL;
+
+ if (unlikely(src->mode == IEEE802154_ADDR_NONE))
+ return -EINVAL;
+
+ if (unlikely(!bh->pan_coordinator))
+ return -ENODEV;
+
+ scan_req = rcu_dereference(local->scan_req);
+ if (unlikely(!scan_req))
+ return -EINVAL;
+
+ if (unlikely(local->scan_channel_idx < 0)) {
+ pr_info("Dropping beacon received during channel change\n");
+ return 0;
+ }
+
+ pr_debug("Beacon received on channel %d of page %d\n",
+ local->scan_channel_idx, scan_req->page);
+
+ /* Parse beacon and create PAN information */
+ desc.coord = src;
+ desc.page = scan_req->page;
+ desc.channel = local->scan_channel_idx;
+ desc.link_quality = mac_cb(skb)->lqi;
+ desc.superframe_spec = get_unaligned_le16(skb->data);
+ desc.gts_permit = bh->gts_permit;
+
+ /* Create or update the PAN entry in the management layer */
+ ret = cfg802154_record_pan(local->phy, &desc);
+ if (ret) {
+ pr_err("Failed to save PAN descriptor\n");
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
index c829e4a75325..40656728c624 100644
--- a/net/mac802154/tx.c
+++ b/net/mac802154/tx.c
@@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
struct net_device *dev = skb->dev;
int ret;
+ if (unlikely(mac802154_scan_is_ongoing(local)))
+ return NETDEV_TX_BUSY;
+
if (!(local->hw.flags & IEEE802154_HW_TX_OMIT_CKSUM)) {
struct sk_buff *nskb;
u16 crc;
diff --git a/net/mac802154/util.c b/net/mac802154/util.c
index f2078238718b..5ee65cb1dbcd 100644
--- a/net/mac802154/util.c
+++ b/net/mac802154/util.c
@@ -94,3 +94,29 @@ void ieee802154_stop_device(struct ieee802154_local *local)
hrtimer_cancel(&local->ifs_timer);
drv_stop(local);
}
+
+/* Nothing should have been stuffed into the workqueue during
+ * the suspend->resume cycle.
+ */
+static bool ieee802154_can_queue_work(struct ieee802154_local *local)
+{
+ if (local->suspended) {
+ pr_warn("queueing ieee802154 work while suspended\n");
+ return false;
+ }
+
+ return true;
+}
+
+void ieee802154_queue_delayed_work(struct ieee802154_hw *hw,
+ struct delayed_work *dwork,
+ unsigned long delay)
+{
+ struct ieee802154_local *local = hw_to_local(hw);
+
+ if (!ieee802154_can_queue_work(local))
+ return;
+
+ queue_delayed_work(local->workqueue, dwork, delay);
+}
+EXPORT_SYMBOL(ieee802154_queue_delayed_work);
--
2.27.0
Hi,
On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
>
> Now that we have access to all the basic information to know which
> symbol duration should be applied, let's set the symbol duration
> automatically. The two locations that must call for the symbol duration
> to be set are:
> - when manually requesting a channel change though the netlink interface
> - at PHY creation, ieee802154_alloc_hw() already calls
> ieee802154_change_channel() which will now update the symbol duration
> accordingly.
>
> If an information is missing, the symbol duration is not touched, a
> debug message is eventually printed. This keeps the compatibility with
> the unconverted drivers for which it was too complicated for me to find
> their precise information. If they initially provided a symbol duration,
> it would be kept. If they don't, the symbol duration value is left
> untouched.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> include/net/cfg802154.h | 2 +
> net/mac802154/cfg.c | 1 +
> net/mac802154/main.c | 93 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 96 insertions(+)
>
> diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> index 286709a9dd0b..52eefc4b5b4d 100644
> --- a/include/net/cfg802154.h
> +++ b/include/net/cfg802154.h
> @@ -455,4 +455,6 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
> return dev_name(&phy->dev);
> }
>
> +void ieee802154_set_symbol_duration(struct wpan_phy *phy);
> +
> #endif /* __NET_CFG802154_H */
> diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> index 6969f1330ccd..ba57da07c08e 100644
> --- a/net/mac802154/cfg.c
> +++ b/net/mac802154/cfg.c
> @@ -113,6 +113,7 @@ int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
> if (!ret) {
> wpan_phy->current_page = page;
> wpan_phy->current_channel = channel;
> + ieee802154_set_symbol_duration(wpan_phy);
> }
>
> return ret;
We also need to do it in ieee802154_register_hw()?
> diff --git a/net/mac802154/main.c b/net/mac802154/main.c
> index 77a4943f345f..88826c5aa4ba 100644
> --- a/net/mac802154/main.c
> +++ b/net/mac802154/main.c
> @@ -113,6 +113,99 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
> }
> EXPORT_SYMBOL(ieee802154_alloc_hw);
>
> +void ieee802154_set_symbol_duration(struct wpan_phy *phy)
> +{
> + struct phy_page *page = &phy->supported.page[phy->current_page];
> + struct phy_channels *chan;
> + unsigned int chunk;
> + u32 duration = 0;
> +
> + for (chunk = 0; chunk < page->nchunks; chunk++) {
> + if (page->chunk[chunk].channels & phy->current_channel)
> + break;
> + }
> +
> + if (chunk == page->nchunks)
> + goto set_duration;
> +
> + chan = &page->chunk[chunk];
> + switch (chan->protocol) {
> + case IEEE802154_BPSK_PHY:
> + switch (chan->band) {
> + case IEEE802154_868_MHZ_BAND:
> + /* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */
> + duration = 50 * 1000;
* NSEC_PER_USEC?
- Alex
Hi,
On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
>
> The core now knows how to set the symbol duration in a few cases, when
> drivers correctly advertise the protocols used on each channel. For
> these drivers, there is no more need to bother with symbol duration, so
> just drop the duplicated code.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/net/ieee802154/ca8210.c | 1 -
> drivers/net/ieee802154/mcr20a.c | 2 --
> 2 files changed, 3 deletions(-)
>
> diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> index 82b2a173bdbd..d3a9e4fe05f4 100644
> --- a/drivers/net/ieee802154/ca8210.c
> +++ b/drivers/net/ieee802154/ca8210.c
> @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> ca8210_hw->phy->cca_ed_level = -9800;
> - ca8210_hw->phy->symbol_duration = 16 * 1000;
> ca8210_hw->phy->lifs_period = 40;
> ca8210_hw->phy->sifs_period = 12;
> ca8210_hw->flags =
> diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> index 8aa87e9bf92e..da2ab19cb5ee 100644
> --- a/drivers/net/ieee802154/mcr20a.c
> +++ b/drivers/net/ieee802154/mcr20a.c
> @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
>
> dev_dbg(printdev(lp), "%s\n", __func__);
>
> - phy->symbol_duration = 16 * 1000;
> phy->lifs_period = 40;
> phy->sifs_period = 12;
>
> @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> phy->current_page = 0;
> /* MCR20A default reset value */
> phy->current_channel = 20;
> - phy->symbol_duration = 16 * 1000;
> phy->supported.tx_powers = mcr20a_powers;
> phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> phy->cca_ed_level = phy->supported.cca_ed_levels[75];
What's about the atrf86230 driver?
- Alex
Hi,
On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
>
> As it is currently designed, the set_channel() cfg802154 hook
> implemented in the softMAC is doing a couple of checks before actually
> performing the channel change. However, as we enhance the support for
> automatically setting the symbol duration during channel changes, it
> will also be needed to ensure that the corresponding channel as properly
> be selected at probe time. In order to verify this, we will need to
no, we don't set channels at probe time. We set the
current_page/channel whatever the default is according to the hardware
datasheet. I think this channel should be dropped and all drivers set
the defaults before registering hw as what we do at e.g. at86rf230,
see [0].
- Alex
[0] https://elixir.bootlin.com/linux/v5.16/source/drivers/net/ieee802154/at86rf230.c#L1553
Hi,
On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
>
> The Cascada 8210 hardware transceiver is kind of a hardMAC which
> interfaces with the softMAC and in practice does not support sending
> anything else than dataframes. This means we cannot send any BEACON_REQ
> during active scans nor any BEACON in general. Refuse these operations
> officially so that the user is aware of the limitation.
>
> Signed-off-by: Miquel Raynal <[email protected]>
> ---
> drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> index d3a9e4fe05f4..49c274280e3c 100644
> --- a/drivers/net/ieee802154/ca8210.c
> +++ b/drivers/net/ieee802154/ca8210.c
> @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> return link_to_linux_err(status);
> }
>
> +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> + struct cfg802154_scan_request *request)
> +{
> + /* This xceiver can only send dataframes */
> + if (request->type != NL802154_SCAN_PASSIVE)
> + return -EOPNOTSUPP;
> +
> + return 0;
> +}
> +
> +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> + struct cfg802154_beacons_request *request)
> +{
> + /* This xceiver can only send dataframes */
> + return -EOPNOTSUPP;
> +}
> +
> +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> +
> static const struct ieee802154_ops ca8210_phy_ops = {
> .start = ca8210_start,
> .stop = ca8210_stop,
> @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> .set_cca_ed_level = ca8210_set_cca_ed_level,
> .set_csma_params = ca8210_set_csma_params,
> .set_frame_retries = ca8210_set_frame_retries,
> - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> + .enter_scan_mode = ca8210_enter_scan_mode,
> + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> + .enter_beacons_mode = ca8210_enter_beacons_mode,
> + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> };
so there is no flag that this driver can't support scanning currently
and it works now because the offload functionality will return
-ENOTSUPP? This is misleading because I would assume if it's not
supported we can do it by software which the driver can't do.
... I see that the offload functions now are getting used and have a
reason to be upstream, but the use of it is wrong.
- Alex
Hi,
On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
...
> + return 0;
> +}
> diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> index c829e4a75325..40656728c624 100644
> --- a/net/mac802154/tx.c
> +++ b/net/mac802154/tx.c
> @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> struct net_device *dev = skb->dev;
> int ret;
>
> + if (unlikely(mac802154_scan_is_ongoing(local)))
> + return NETDEV_TX_BUSY;
> +
Please look into the functions "ieee802154_wake_queue()" and
"ieee802154_stop_queue()" which prevent this function from being
called. Call stop before starting scanning and wake after scanning is
done or stopped.
Also there exists a race which exists in your way and also the one
mentioned above. There can still be some transmissions going on... We
need to wait until "all possible" tx completions are done... to be
sure there are really no transmissions going on. However we need to be
sure that a wake cannot be done if a tx completion is done, we need to
avoid it when the scan operation is ongoing as a workaround for this
race.
This race exists and should be fixed in future work?
- Alex
Hi,
On Wed, 12 Jan 2022 at 17:30, Alexander Aring <[email protected]> wrote:
>
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> >
> > As it is currently designed, the set_channel() cfg802154 hook
> > implemented in the softMAC is doing a couple of checks before actually
> > performing the channel change. However, as we enhance the support for
> > automatically setting the symbol duration during channel changes, it
> > will also be needed to ensure that the corresponding channel as properly
> > be selected at probe time. In order to verify this, we will need to
>
> no, we don't set channels at probe time. We set the
> current_page/channel whatever the default is according to the hardware
> datasheet. I think this channel should be dropped and all drivers set
s/channel/patch/
- Alex
Hi,
On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
...
> +static int mac802154_scan_send_beacon_req_locked(struct ieee802154_local *local)
> +{
> + struct sk_buff *skb;
> + int ret;
> +
> + lockdep_assert_held(&local->scan_lock);
> +
> + skb = alloc_skb(IEEE802154_BEACON_REQ_SKB_SZ, GFP_KERNEL);
> + if (!skb)
> + return -ENOBUFS;
> +
> + ret = ieee802154_beacon_req_push(skb, &local->beacon_req);
> + if (ret) {
> + kfree_skb(skb);
> + return ret;
> + }
> +
> + return drv_xmit_async(local, skb);
I think you need to implement a sync transmit handling here. And what
I mean is not using dryv_xmit_sync() (It is a long story and should
not be used, it's just that the driver is allowed to call bus api
functions which can sleep). We don't have such a function yet (but I
think it can be implemented), you should wait until the transmission
is done. If we don't wait we fill framebuffers on the hardware while
the hardware is transmitting the framebuffer which is... bad.
Please implement it so that we have a synchronous api above the
asynchronous transmit api.
- Alex
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:30:35 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> >
> > As it is currently designed, the set_channel() cfg802154 hook
> > implemented in the softMAC is doing a couple of checks before actually
> > performing the channel change. However, as we enhance the support for
> > automatically setting the symbol duration during channel changes, it
> > will also be needed to ensure that the corresponding channel as properly
> > be selected at probe time. In order to verify this, we will need to
>
> no, we don't set channels at probe time. We set the
> current_page/channel whatever the default is according to the hardware
> datasheet. I think this channel should be dropped and all drivers set
> the defaults before registering hw as what we do at e.g. at86rf230,
> see [0].
Is there a reason for refusing to call ->set_channel() at probe time?
Anyway, I'll put the symbol duration setting in the registration helper
and I will fix hwsim aside.
>
> - Alex
>
> [0] https://elixir.bootlin.com/linux/v5.16/source/drivers/net/ieee802154/at86rf230.c#L1553
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:48:59 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> >
> > The Cascada 8210 hardware transceiver is kind of a hardMAC which
> > interfaces with the softMAC and in practice does not support sending
> > anything else than dataframes. This means we cannot send any BEACON_REQ
> > during active scans nor any BEACON in general. Refuse these operations
> > officially so that the user is aware of the limitation.
> >
> > Signed-off-by: Miquel Raynal <[email protected]>
> > ---
> > drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> > 1 file changed, 24 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > index d3a9e4fe05f4..49c274280e3c 100644
> > --- a/drivers/net/ieee802154/ca8210.c
> > +++ b/drivers/net/ieee802154/ca8210.c
> > @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> > return link_to_linux_err(status);
> > }
> >
> > +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> > + struct cfg802154_scan_request *request)
> > +{
> > + /* This xceiver can only send dataframes */
> > + if (request->type != NL802154_SCAN_PASSIVE)
> > + return -EOPNOTSUPP;
> > +
> > + return 0;
> > +}
> > +
> > +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> > + struct cfg802154_beacons_request *request)
> > +{
> > + /* This xceiver can only send dataframes */
> > + return -EOPNOTSUPP;
> > +}
> > +
> > +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> > +
> > static const struct ieee802154_ops ca8210_phy_ops = {
> > .start = ca8210_start,
> > .stop = ca8210_stop,
> > @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> > .set_cca_ed_level = ca8210_set_cca_ed_level,
> > .set_csma_params = ca8210_set_csma_params,
> > .set_frame_retries = ca8210_set_frame_retries,
> > - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> > + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> > + .enter_scan_mode = ca8210_enter_scan_mode,
> > + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> > + .enter_beacons_mode = ca8210_enter_beacons_mode,
> > + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> > };
>
> so there is no flag that this driver can't support scanning currently
> and it works now because the offload functionality will return
> -ENOTSUPP? This is misleading because I would assume if it's not
> supported we can do it by software which the driver can't do.
I believe there is a misunderstanding.
This is what I have understood from your previous comments in v1:
"This driver does not support transmitting anything else than
datagrams", which is what I assumed was a regular data packet. IOW,
sending a MAC_CMD such as a beacon request or sending a beacon was not
supported physically by the hardware. Hence, most of the scans
operations cannot be performed and must be rejected (all but a passive
scan, assuming that receiving beacons was okay).
Please mind the update in that hook which currently is just an FYI from
the mac to the drivers and not a "do it by yourself" injunction. So
answering -EOPNOTSUPP to the mac here does not mean:
"I cannot handle it by myself, the scan cannot happen"
but
"I cannot handle the forged frames, so let's just not try"
> ... I see that the offload functions now are getting used and have a
> reason to be upstream, but the use of it is wrong.
As a personal matter of taste, I don't like flags when it comes to
something complex like supporting a specific operation. Just in the
scanning procedure there are 4 different actions and a driver might
support only a subset of these, which is totally fine but hard to
properly describe by well-named flags. Here the driver hooks say to
the driver which are interested "here is what is going to happen" and
then they can:
- ignore the details by just not implementing the hooks, let the mac do
its job, they will then transmit the relevant frames forged by the
mac
- eventually enter a specific mode internally for this operation, but
basically do the same as above, ie. transmitting the frames forged
by the mac
- refuse the operation by returning an error code if something cannot
be done
I've experienced a number of situations in the MTD world and later with
IIO drivers where flags have been remodeled and reused in different
manners, until the flag description gets totally wrong and
undescriptive regarding what it actually does. Hence my main idea of
letting drivers refuse these operations instead of having the mac doing
it for them.
I can definitely use flags if you want, but in this case, what flags do
you want to see?
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:25:01 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> >
> > Now that we have access to all the basic information to know which
> > symbol duration should be applied, let's set the symbol duration
> > automatically. The two locations that must call for the symbol duration
> > to be set are:
> > - when manually requesting a channel change though the netlink interface
> > - at PHY creation, ieee802154_alloc_hw() already calls
> > ieee802154_change_channel() which will now update the symbol duration
> > accordingly.
> >
> > If an information is missing, the symbol duration is not touched, a
> > debug message is eventually printed. This keeps the compatibility with
> > the unconverted drivers for which it was too complicated for me to find
> > their precise information. If they initially provided a symbol duration,
> > it would be kept. If they don't, the symbol duration value is left
> > untouched.
> >
> > Signed-off-by: Miquel Raynal <[email protected]>
> > ---
> > include/net/cfg802154.h | 2 +
> > net/mac802154/cfg.c | 1 +
> > net/mac802154/main.c | 93 +++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 96 insertions(+)
> >
> > diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h
> > index 286709a9dd0b..52eefc4b5b4d 100644
> > --- a/include/net/cfg802154.h
> > +++ b/include/net/cfg802154.h
> > @@ -455,4 +455,6 @@ static inline const char *wpan_phy_name(struct wpan_phy *phy)
> > return dev_name(&phy->dev);
> > }
> >
> > +void ieee802154_set_symbol_duration(struct wpan_phy *phy);
> > +
> > #endif /* __NET_CFG802154_H */
> > diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c
> > index 6969f1330ccd..ba57da07c08e 100644
> > --- a/net/mac802154/cfg.c
> > +++ b/net/mac802154/cfg.c
> > @@ -113,6 +113,7 @@ int ieee802154_change_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
> > if (!ret) {
> > wpan_phy->current_page = page;
> > wpan_phy->current_channel = channel;
> > + ieee802154_set_symbol_duration(wpan_phy);
> > }
> >
> > return ret;
>
> We also need to do it in ieee802154_register_hw()?
As you probably saw, my idea was to call for a channel change during
the registration but you nacked that possibility so I'll indeed have
to set the symbol duration manually there.
> > diff --git a/net/mac802154/main.c b/net/mac802154/main.c
> > index 77a4943f345f..88826c5aa4ba 100644
> > --- a/net/mac802154/main.c
> > +++ b/net/mac802154/main.c
> > @@ -113,6 +113,99 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
> > }
> > EXPORT_SYMBOL(ieee802154_alloc_hw);
> >
> > +void ieee802154_set_symbol_duration(struct wpan_phy *phy)
> > +{
> > + struct phy_page *page = &phy->supported.page[phy->current_page];
> > + struct phy_channels *chan;
> > + unsigned int chunk;
> > + u32 duration = 0;
> > +
> > + for (chunk = 0; chunk < page->nchunks; chunk++) {
> > + if (page->chunk[chunk].channels & phy->current_channel)
.channels still being a bitfield, David allegedly reported that the
above line should use "& BIT(phy->current_channel)".
> > + break;
> > + }
> > +
> > + if (chunk == page->nchunks)
> > + goto set_duration;
> > +
> > + chan = &page->chunk[chunk];
> > + switch (chan->protocol) {
> > + case IEEE802154_BPSK_PHY:
> > + switch (chan->band) {
> > + case IEEE802154_868_MHZ_BAND:
> > + /* 868 MHz BPSK 802.15.4-2003: 20 ksym/s */
> > + duration = 50 * 1000;
>
> * NSEC_PER_USEC?
Oh right, I grepped for USEC_TO_NSEC but the macro was named the other
way around, thanks.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:53:57 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 17:30, Alexander Aring <[email protected]> wrote:
> >
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > >
> > > As it is currently designed, the set_channel() cfg802154 hook
> > > implemented in the softMAC is doing a couple of checks before actually
> > > performing the channel change. However, as we enhance the support for
> > > automatically setting the symbol duration during channel changes, it
> > > will also be needed to ensure that the corresponding channel as properly
> > > be selected at probe time. In order to verify this, we will need to
> >
> > no, we don't set channels at probe time. We set the
> > current_page/channel whatever the default is according to the hardware
> > datasheet. I think this channel should be dropped and all drivers set
>
> s/channel/patch/
I've dropped the patch and put an additional call to
_set_symbol_duration() in the hw registration routine as discussed
initially.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> >
> > The core now knows how to set the symbol duration in a few cases, when
> > drivers correctly advertise the protocols used on each channel. For
> > these drivers, there is no more need to bother with symbol duration, so
> > just drop the duplicated code.
> >
> > Signed-off-by: Miquel Raynal <[email protected]>
> > ---
> > drivers/net/ieee802154/ca8210.c | 1 -
> > drivers/net/ieee802154/mcr20a.c | 2 --
> > 2 files changed, 3 deletions(-)
> >
> > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > --- a/drivers/net/ieee802154/ca8210.c
> > +++ b/drivers/net/ieee802154/ca8210.c
> > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > ca8210_hw->phy->cca_ed_level = -9800;
> > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > ca8210_hw->phy->lifs_period = 40;
> > ca8210_hw->phy->sifs_period = 12;
> > ca8210_hw->flags =
> > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > --- a/drivers/net/ieee802154/mcr20a.c
> > +++ b/drivers/net/ieee802154/mcr20a.c
> > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> >
> > dev_dbg(printdev(lp), "%s\n", __func__);
> >
> > - phy->symbol_duration = 16 * 1000;
> > phy->lifs_period = 40;
> > phy->sifs_period = 12;
> >
> > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > phy->current_page = 0;
> > /* MCR20A default reset value */
> > phy->current_channel = 20;
> > - phy->symbol_duration = 16 * 1000;
> > phy->supported.tx_powers = mcr20a_powers;
> > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
>
> What's about the atrf86230 driver?
I couldn't find reliable information about what this meant:
/* SUB:0 and BPSK:0 -> BPSK-20 */
/* SUB:1 and BPSK:0 -> BPSK-40 */
/* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
/* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
None of these comments match the spec so I don't know what to put
there. If you know what these protocols are, I will immediately
provide this information into the driver and ensure the core handles
these durations properly before dropping the symbol_durations settings
from the code.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> ...
> > + return 0;
> > +}
> > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > index c829e4a75325..40656728c624 100644
> > --- a/net/mac802154/tx.c
> > +++ b/net/mac802154/tx.c
> > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > struct net_device *dev = skb->dev;
> > int ret;
> >
> > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > + return NETDEV_TX_BUSY;
> > +
>
> Please look into the functions "ieee802154_wake_queue()" and
> "ieee802154_stop_queue()" which prevent this function from being
> called. Call stop before starting scanning and wake after scanning is
> done or stopped.
Mmmh all this is already done, isn't it?
- mac802154_trigger_scan_locked() stops the queue before setting the
promiscuous mode
- mac802154_end_of_scan() wakes the queue after resetting the
promiscuous mode to its original state
Should I drop the check which stands for an extra precaution?
But overall I think I don't understand well this part. What is
a bit foggy to me is why the (async) tx implementation does:
*Core* *Driver*
stop_queue()
drv_async_xmit() -------
\------> do something
------- calls ieee802154_xmit_complete()
wakeup_queue() <--------/
So we actually disable the queue for transmitting. Why??
> Also there exists a race which exists in your way and also the one
> mentioned above. There can still be some transmissions going on... We
> need to wait until "all possible" tx completions are done... to be
> sure there are really no transmissions going on. However we need to be
> sure that a wake cannot be done if a tx completion is done, we need to
> avoid it when the scan operation is ongoing as a workaround for this
> race.
>
> This race exists and should be fixed in future work?
Yep, this is true, do you have any pointers? Because I looked at the
code and for now it appears quite unpractical to add some kind of
flushing mechanism on that net queue. I believe we cannot use the netif
interface for that so we would have to implement our own mechanism in
the ieee802154 core.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Wed, 12 Jan 2022 18:16:11 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> ...
> > +static int mac802154_scan_send_beacon_req_locked(struct ieee802154_local *local)
> > +{
> > + struct sk_buff *skb;
> > + int ret;
> > +
> > + lockdep_assert_held(&local->scan_lock);
> > +
> > + skb = alloc_skb(IEEE802154_BEACON_REQ_SKB_SZ, GFP_KERNEL);
> > + if (!skb)
> > + return -ENOBUFS;
> > +
> > + ret = ieee802154_beacon_req_push(skb, &local->beacon_req);
> > + if (ret) {
> > + kfree_skb(skb);
> > + return ret;
> > + }
> > +
> > + return drv_xmit_async(local, skb);
>
> I think you need to implement a sync transmit handling here.
True.
> And what
> I mean is not using dryv_xmit_sync() (It is a long story and should
> not be used, it's just that the driver is allowed to call bus api
> functions which can sleep).
Understood.
> We don't have such a function yet (but I
> think it can be implemented), you should wait until the transmission
> is done. If we don't wait we fill framebuffers on the hardware while
> the hardware is transmitting the framebuffer which is... bad.
Do you already have something in mind?
If I focus on the scan operation, it could be that we consider the
queue empty, then we put this transfer, wait for completion and
continue. But this only work for places where we know we have full
control over what is transmitted (eg. during a scan) and not for all
transfers. Would this fit your idea?
Or do you want something more generic with some kind of an
internal queue where we have the knowledge of what has been queued and
a token to link with every xmit_done call that is made?
I'm open to suggestions.
Thanks,
Miquèl
Hi,
On Thu, 13 Jan 2022 at 04:32, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Wed, 12 Jan 2022 17:30:35 -0500:
>
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > >
> > > As it is currently designed, the set_channel() cfg802154 hook
> > > implemented in the softMAC is doing a couple of checks before actually
> > > performing the channel change. However, as we enhance the support for
> > > automatically setting the symbol duration during channel changes, it
> > > will also be needed to ensure that the corresponding channel as properly
> > > be selected at probe time. In order to verify this, we will need to
> >
> > no, we don't set channels at probe time. We set the
> > current_page/channel whatever the default is according to the hardware
> > datasheet. I think this channel should be dropped and all drivers set
> > the defaults before registering hw as what we do at e.g. at86rf230,
> > see [0].
>
> Is there a reason for refusing to call ->set_channel() at probe time?
>
because the current drivers work the way to not set the channel/page
during probe time. Also the 802.15.4 spec states that this default
value is hardware specific and this goes back whatever the vendor
decides. Also you drop the check that if the same channel is already
set don't set it which works like a shadow register for registers.
Is there a reason why to set a channel during probe time? Are you
setting the value which is the default one again? If the driver has a
random default value it should choose some and stick to one, the
others do whatever the datasheet has after resetting the hardware.
I really don't see the sense here why every driver should introduce on
driver level a set channel call. At probing time the transceiver
registers are already in a state which we should reflect.
> Anyway, I'll put the symbol duration setting in the registration helper
> and I will fix hwsim aside.
>
ok, thanks.
- Alex
Hi,
On Thu, 13 Jan 2022 at 06:16, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
>
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > >
> > > The core now knows how to set the symbol duration in a few cases, when
> > > drivers correctly advertise the protocols used on each channel. For
> > > these drivers, there is no more need to bother with symbol duration, so
> > > just drop the duplicated code.
> > >
> > > Signed-off-by: Miquel Raynal <[email protected]>
> > > ---
> > > drivers/net/ieee802154/ca8210.c | 1 -
> > > drivers/net/ieee802154/mcr20a.c | 2 --
> > > 2 files changed, 3 deletions(-)
> > >
> > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > > --- a/drivers/net/ieee802154/ca8210.c
> > > +++ b/drivers/net/ieee802154/ca8210.c
> > > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > > ca8210_hw->phy->cca_ed_level = -9800;
> > > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > > ca8210_hw->phy->lifs_period = 40;
> > > ca8210_hw->phy->sifs_period = 12;
> > > ca8210_hw->flags =
> > > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > > --- a/drivers/net/ieee802154/mcr20a.c
> > > +++ b/drivers/net/ieee802154/mcr20a.c
> > > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > >
> > > dev_dbg(printdev(lp), "%s\n", __func__);
> > >
> > > - phy->symbol_duration = 16 * 1000;
> > > phy->lifs_period = 40;
> > > phy->sifs_period = 12;
> > >
> > > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > phy->current_page = 0;
> > > /* MCR20A default reset value */
> > > phy->current_channel = 20;
> > > - phy->symbol_duration = 16 * 1000;
> > > phy->supported.tx_powers = mcr20a_powers;
> > > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
> >
> > What's about the atrf86230 driver?
>
> I couldn't find reliable information about what this meant:
>
> /* SUB:0 and BPSK:0 -> BPSK-20 */
> /* SUB:1 and BPSK:0 -> BPSK-40 */
> /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
> /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
>
> None of these comments match the spec so I don't know what to put
> there. If you know what these protocols are, I will immediately
> provide this information into the driver and ensure the core handles
> these durations properly before dropping the symbol_durations settings
> from the code.
I think those are from the transceiver datasheets (which are free to
access). Can you not simply merge them or is there a conflict?
- Alex
Hi,
On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
...
> + case IEEE802154_4030KHZ_MEAN_PRF:
> + duration = 3974;
> + break;
> + case IEEE802154_62890KHZ_MEAN_PRF:
> + duration = 1018;
> + break;
> + default:
> + break;
> + }
> + break;
> + default:
> + break;
> + }
> +
> +set_duration:
> + if (!duration)
> + pr_debug("Unknown PHY symbol duration, the driver should be fixed\n");
Why should the driver be fixed? It's more this table which needs to be fixed?
> + else
> + phy->symbol_duration = duration;
Can you also set the lifs/sifs period after the duration is known?
- Alex
Hi,
On Thu, 13 Jan 2022 at 12:07, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
>
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > ...
> > > + return 0;
> > > +}
> > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > > index c829e4a75325..40656728c624 100644
> > > --- a/net/mac802154/tx.c
> > > +++ b/net/mac802154/tx.c
> > > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > > struct net_device *dev = skb->dev;
> > > int ret;
> > >
> > > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > > + return NETDEV_TX_BUSY;
> > > +
> >
> > Please look into the functions "ieee802154_wake_queue()" and
> > "ieee802154_stop_queue()" which prevent this function from being
> > called. Call stop before starting scanning and wake after scanning is
> > done or stopped.
>
> Mmmh all this is already done, isn't it?
> - mac802154_trigger_scan_locked() stops the queue before setting the
> promiscuous mode
> - mac802154_end_of_scan() wakes the queue after resetting the
> promiscuous mode to its original state
>
> Should I drop the check which stands for an extra precaution?
>
no, I think then it should be a WARN_ON() more without any return
(hopefully it will survive). This case should never happen otherwise
we have a bug that we wake the queue when we "took control about
transmissions" only.
Change the name, I think it will be in future not only scan related.
Maybe "mac802154_queue_stopped()". Everything which is queued from
socket/upperlayer(6lowpan) goes this way.
>
> But overall I think I don't understand well this part. What is
> a bit foggy to me is why the (async) tx implementation does:
>
> *Core* *Driver*
>
> stop_queue()
> drv_async_xmit() -------
> \------> do something
> ------- calls ieee802154_xmit_complete()
> wakeup_queue() <--------/
>
> So we actually disable the queue for transmitting. Why??
>
Because all transceivers have either _one_ transmit framebuffer or one
framebuffer for transmit and receive one time. We need to report to
stop giving us more skb's while we are busy with one to transmit.
This all will/must be changed in future if there is hardware outside
which is more powerful and the driver needs to control the flow here.
That ieee802154_xmit_complete() calls wakeup_queue need to be
forbidden when we are in "synchronous transmit mode"/the queue is
stopped. The synchronous transmit mode is not for any hotpath, it's
for MLME and I think we also need a per phy lock to avoid multiple
synchronous transmissions at one time. Please note that I don't think
here only about scan operation, also for other possible MLME-ops.
> > Also there exists a race which exists in your way and also the one
> > mentioned above. There can still be some transmissions going on... We
> > need to wait until "all possible" tx completions are done... to be
> > sure there are really no transmissions going on. However we need to be
> > sure that a wake cannot be done if a tx completion is done, we need to
> > avoid it when the scan operation is ongoing as a workaround for this
> > race.
> >
> > This race exists and should be fixed in future work?
>
> Yep, this is true, do you have any pointers? Because I looked at the
> code and for now it appears quite unpractical to add some kind of
> flushing mechanism on that net queue. I believe we cannot use the netif
> interface for that so we would have to implement our own mechanism in
> the ieee802154 core.
yes, we need some kind of "wait_for_completion()" and "complete()". We
are currently lucky that we allow only one skb to be transmitted at
one time. I think it is okay to put that on a per phy basis...
- Alex
Hi,
On Thu, 13 Jan 2022 at 12:14, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Wed, 12 Jan 2022 18:16:11 -0500:
>
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > ...
> > > +static int mac802154_scan_send_beacon_req_locked(struct ieee802154_local *local)
> > > +{
> > > + struct sk_buff *skb;
> > > + int ret;
> > > +
> > > + lockdep_assert_held(&local->scan_lock);
> > > +
> > > + skb = alloc_skb(IEEE802154_BEACON_REQ_SKB_SZ, GFP_KERNEL);
> > > + if (!skb)
> > > + return -ENOBUFS;
> > > +
> > > + ret = ieee802154_beacon_req_push(skb, &local->beacon_req);
> > > + if (ret) {
> > > + kfree_skb(skb);
> > > + return ret;
> > > + }
> > > +
> > > + return drv_xmit_async(local, skb);
> >
> > I think you need to implement a sync transmit handling here.
>
> True.
>
> > And what
> > I mean is not using dryv_xmit_sync() (It is a long story and should
> > not be used, it's just that the driver is allowed to call bus api
> > functions which can sleep).
>
> Understood.
>
I think we should care about drivers which use drv_xmit_sync() or we
disable scan operations for them... so the actual transmit function
should prefer async but use sync if it's not implemented. I am not a
fan of this inside the core, if some driver really want to workaround
their bus system because it's simpler to use or whatever they should
do that inside the driver and not let the core queue it for them in
the right context. There are reasons why xmit_do is in softirq
context.
> > We don't have such a function yet (but I
> > think it can be implemented), you should wait until the transmission
> > is done. If we don't wait we fill framebuffers on the hardware while
> > the hardware is transmitting the framebuffer which is... bad.
>
> Do you already have something in mind?
>
> If I focus on the scan operation, it could be that we consider the
> queue empty, then we put this transfer, wait for completion and
> continue. But this only work for places where we know we have full
> control over what is transmitted (eg. during a scan) and not for all
> transfers. Would this fit your idea?
>
> Or do you want something more generic with some kind of an
> internal queue where we have the knowledge of what has been queued and
> a token to link with every xmit_done call that is made?
>
> I'm open to suggestions.
>
That we currently allow only one skb at one time (because ?all?
supported hardware doesn't have multiple tx framebuffers) this makes
everything for now pretty simple.
Don't let the queue run empty, the queue here is controlled by the
qdsic (I suppose and I hope we are talking about the same queue) we
already stop the queue which stops further skb to transmit to the
hardware but there can be one ongoing which we need to wait for. I
said in a previous mail a wait_for_completion()/complete() works here,
but I think now that could be problematic because scan-op ->
wait_for_completion() and complete() can run parallel in different
contexts. I think we need to do that over a waitqueue and a
wait_event(). Maybe you can track somehow with an atomic counter how
many transmissions are currently ongoing (should be never higher than
one currently). However the atomic counter will be future proofed when
we support filling up more than one framebuffer. So the condition for
wait_event() would be atomic_test(phy->ongoing_txs) - or something
like that. Increment in transmit path and decrement in xmit_done path,
if it hits zero wake_up() the queue so the condition will be checked
again.
That the queue is controlled by qdisc and we stop the queue for a long
time will somehow act the qdisc badly and dropping skb's in the
"hotpath" as I mentioned earlier it should be okay.
Be sure we don't activate the queue again in the xmit complete
function, if we do the WARN_ON(mac...queue_stopped()) should be
triggered and this indicates we were not expecting to transmit
something over this path.
- Alex
Hi,
On Thu, 13 Jan 2022 at 19:30, Alexander Aring <[email protected]> wrote:
>
> Hi,
>
> On Thu, 13 Jan 2022 at 12:14, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Wed, 12 Jan 2022 18:16:11 -0500:
> >
> > > Hi,
> > >
> > > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > > ...
> > > > +static int mac802154_scan_send_beacon_req_locked(struct ieee802154_local *local)
> > > > +{
> > > > + struct sk_buff *skb;
> > > > + int ret;
> > > > +
> > > > + lockdep_assert_held(&local->scan_lock);
> > > > +
> > > > + skb = alloc_skb(IEEE802154_BEACON_REQ_SKB_SZ, GFP_KERNEL);
> > > > + if (!skb)
> > > > + return -ENOBUFS;
> > > > +
> > > > + ret = ieee802154_beacon_req_push(skb, &local->beacon_req);
> > > > + if (ret) {
> > > > + kfree_skb(skb);
> > > > + return ret;
> > > > + }
> > > > +
> > > > + return drv_xmit_async(local, skb);
> > >
> > > I think you need to implement a sync transmit handling here.
> >
> > True.
> >
> > > And what
> > > I mean is not using dryv_xmit_sync() (It is a long story and should
> > > not be used, it's just that the driver is allowed to call bus api
> > > functions which can sleep).
> >
> > Understood.
> >
>
> I think we should care about drivers which use drv_xmit_sync() or we
> disable scan operations for them... so the actual transmit function
> should prefer async but use sync if it's not implemented. I am not a
> fan of this inside the core, if some driver really want to workaround
> their bus system because it's simpler to use or whatever they should
> do that inside the driver and not let the core queue it for them in
> the right context. There are reasons why xmit_do is in softirq
> context.
>
> > > We don't have such a function yet (but I
> > > think it can be implemented), you should wait until the transmission
> > > is done. If we don't wait we fill framebuffers on the hardware while
> > > the hardware is transmitting the framebuffer which is... bad.
> >
> > Do you already have something in mind?
> >
> > If I focus on the scan operation, it could be that we consider the
> > queue empty, then we put this transfer, wait for completion and
> > continue. But this only work for places where we know we have full
> > control over what is transmitted (eg. during a scan) and not for all
> > transfers. Would this fit your idea?
> >
> > Or do you want something more generic with some kind of an
> > internal queue where we have the knowledge of what has been queued and
> > a token to link with every xmit_done call that is made?
> >
> > I'm open to suggestions.
> >
>
> That we currently allow only one skb at one time (because ?all?
> supported hardware doesn't have multiple tx framebuffers) this makes
> everything for now pretty simple.
>
> Don't let the queue run empty, the queue here is controlled by the
> qdsic (I suppose and I hope we are talking about the same queue) we
> already stop the queue which stops further skb to transmit to the
> hardware but there can be one ongoing which we need to wait for. I
> said in a previous mail a wait_for_completion()/complete() works here,
> but I think now that could be problematic because scan-op ->
> wait_for_completion() and complete() can run parallel in different
> contexts. I think we need to do that over a waitqueue and a
> wait_event(). Maybe you can track somehow with an atomic counter how
> many transmissions are currently ongoing (should be never higher than
> one currently). However the atomic counter will be future proofed when
> we support filling up more than one framebuffer. So the condition for
> wait_event() would be atomic_test(phy->ongoing_txs) - or something
> like that. Increment in transmit path and decrement in xmit_done path,
> if it hits zero wake_up() the queue so the condition will be checked
> again.
>
I am sorry, the wait_event() will fix the issue after calling
stop_queue() to be sure there are no ongoing transmissions. Now we
need to have some idea about how to implement the synchronous transmit
function. We have the function (drv_xmit_async, or something higher
level to take care of sync as well) to transmit a skb and the complete
handler is xmit_complete(). As I mentioned we allow only one skb for
one time... Somehow we need to have a wait here and a per phy
wait_for_completion()/complete() will in this case work. Even if there
is hardware outside which has more transmit buffers, we probably would
send one skb at one for slowpath (having full control of
transmissions) anyway.
- Alex
Hi,
On Thu, 13 Jan 2022 at 04:30, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Wed, 12 Jan 2022 17:48:59 -0500:
>
> > Hi,
> >
> > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > >
> > > The Cascada 8210 hardware transceiver is kind of a hardMAC which
> > > interfaces with the softMAC and in practice does not support sending
> > > anything else than dataframes. This means we cannot send any BEACON_REQ
> > > during active scans nor any BEACON in general. Refuse these operations
> > > officially so that the user is aware of the limitation.
> > >
> > > Signed-off-by: Miquel Raynal <[email protected]>
> > > ---
> > > drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> > > 1 file changed, 24 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > index d3a9e4fe05f4..49c274280e3c 100644
> > > --- a/drivers/net/ieee802154/ca8210.c
> > > +++ b/drivers/net/ieee802154/ca8210.c
> > > @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> > > return link_to_linux_err(status);
> > > }
> > >
> > > +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> > > + struct cfg802154_scan_request *request)
> > > +{
> > > + /* This xceiver can only send dataframes */
> > > + if (request->type != NL802154_SCAN_PASSIVE)
> > > + return -EOPNOTSUPP;
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> > > + struct cfg802154_beacons_request *request)
> > > +{
> > > + /* This xceiver can only send dataframes */
> > > + return -EOPNOTSUPP;
> > > +}
> > > +
> > > +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> > > +
> > > static const struct ieee802154_ops ca8210_phy_ops = {
> > > .start = ca8210_start,
> > > .stop = ca8210_stop,
> > > @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> > > .set_cca_ed_level = ca8210_set_cca_ed_level,
> > > .set_csma_params = ca8210_set_csma_params,
> > > .set_frame_retries = ca8210_set_frame_retries,
> > > - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> > > + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> > > + .enter_scan_mode = ca8210_enter_scan_mode,
> > > + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> > > + .enter_beacons_mode = ca8210_enter_beacons_mode,
> > > + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> > > };
> >
> > so there is no flag that this driver can't support scanning currently
> > and it works now because the offload functionality will return
> > -ENOTSUPP? This is misleading because I would assume if it's not
> > supported we can do it by software which the driver can't do.
>
> I believe there is a misunderstanding.
>
> This is what I have understood from your previous comments in v1:
> "This driver does not support transmitting anything else than
> datagrams", which is what I assumed was a regular data packet. IOW,
> sending a MAC_CMD such as a beacon request or sending a beacon was not
> supported physically by the hardware. Hence, most of the scans
> operations cannot be performed and must be rejected (all but a passive
> scan, assuming that receiving beacons was okay).
>
and I said that this driver is a HardMAC transceiver connected to the
SoftMAC layer which is already wrong to exist (very special handling
is required here).
dataframes here are "data" type frames and I suppose it's also not
able to deliver/receive other types than data to mac802154.
It seems the author of this driver is happy to have data frames only
but we need to take care that additional mac802154 handling is simply
not possible to do here.
> Please mind the update in that hook which currently is just an FYI from
> the mac to the drivers and not a "do it by yourself" injunction. So
> answering -EOPNOTSUPP to the mac here does not mean:
> "I cannot handle it by myself, the scan cannot happen"
> but
> "I cannot handle the forged frames, so let's just not try"
>
The problem here is that a SoftMAC transceiver should always be
capable of doing it by software so the "but case" makes no sense in
this layer.
On a mac802154 layer and "offload" driver functions as they are and
they report me "-ENOTSUPP", I would assume that I can go back and do
it by software which again should always be possible to do in
mac802154.
> > ... I see that the offload functions now are getting used and have a
> > reason to be upstream, but the use of it is wrong.
>
> As a personal matter of taste, I don't like flags when it comes to
> something complex like supporting a specific operation. Just in the
> scanning procedure there are 4 different actions and a driver might
> support only a subset of these, which is totally fine but hard to
> properly describe by well-named flags. Here the driver hooks say to
> the driver which are interested "here is what is going to happen" and
> then they can:
> - ignore the details by just not implementing the hooks, let the mac do
> its job, they will then transmit the relevant frames forged by the
> mac
> - eventually enter a specific mode internally for this operation, but
> basically do the same as above, ie. transmitting the frames forged
> by the mac
> - refuse the operation by returning an error code if something cannot
> be done
>
> I've experienced a number of situations in the MTD world and later with
> IIO drivers where flags have been remodeled and reused in different
> manners, until the flag description gets totally wrong and
> undescriptive regarding what it actually does. Hence my main idea of
> letting drivers refuse these operations instead of having the mac doing
> it for them.
>
> I can definitely use flags if you want, but in this case, what flags do
> you want to see?
>
Do some phy quirks flags which indicate that the transceiver is not
capable of doing scan operation by software. Or just use a boolean in
phy capabilities (but don't export them to userspace, note that this
flag should be removed later) if this operation is not allowed.
I don't like this flag either, it is a workaround to still support the
driver as it is and don't allow new fancy things because it cannot
handle it. We should work on it to remove this flag, but this is a
longer process. Either the driver is implementing those hooks "real"
to somehow run a scan (but at it's own risk) or it needs to be
implemented as a HardMAC driver. This driver is already difficult to
maintain because it doesn't fit here...
- Alex
Hi Alexander,
[email protected] wrote on Thu, 13 Jan 2022 18:36:15 -0500:
> Hi,
>
> On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> ...
> > + case IEEE802154_4030KHZ_MEAN_PRF:
> > + duration = 3974;
> > + break;
> > + case IEEE802154_62890KHZ_MEAN_PRF:
> > + duration = 1018;
> > + break;
> > + default:
> > + break;
> > + }
> > + break;
> > + default:
> > + break;
> > + }
> > +
> > +set_duration:
> > + if (!duration)
> > + pr_debug("Unknown PHY symbol duration, the driver should be fixed\n");
>
> Why should the driver be fixed? It's more this table which needs to be fixed?
Right.
>
> > + else
> > + phy->symbol_duration = duration;
>
> Can you also set the lifs/sifs period after the duration is known?
Done.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Thu, 13 Jan 2022 18:34:00 -0500:
> Hi,
>
> On Thu, 13 Jan 2022 at 06:16, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
> >
> > > Hi,
> > >
> > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > The core now knows how to set the symbol duration in a few cases, when
> > > > drivers correctly advertise the protocols used on each channel. For
> > > > these drivers, there is no more need to bother with symbol duration, so
> > > > just drop the duplicated code.
> > > >
> > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > ---
> > > > drivers/net/ieee802154/ca8210.c | 1 -
> > > > drivers/net/ieee802154/mcr20a.c | 2 --
> > > > 2 files changed, 3 deletions(-)
> > > >
> > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > > > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > > > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > > > ca8210_hw->phy->cca_ed_level = -9800;
> > > > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > > > ca8210_hw->phy->lifs_period = 40;
> > > > ca8210_hw->phy->sifs_period = 12;
> > > > ca8210_hw->flags =
> > > > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > > > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > > > --- a/drivers/net/ieee802154/mcr20a.c
> > > > +++ b/drivers/net/ieee802154/mcr20a.c
> > > > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > >
> > > > dev_dbg(printdev(lp), "%s\n", __func__);
> > > >
> > > > - phy->symbol_duration = 16 * 1000;
> > > > phy->lifs_period = 40;
> > > > phy->sifs_period = 12;
> > > >
> > > > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > phy->current_page = 0;
> > > > /* MCR20A default reset value */
> > > > phy->current_channel = 20;
> > > > - phy->symbol_duration = 16 * 1000;
> > > > phy->supported.tx_powers = mcr20a_powers;
> > > > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > > > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
> > >
> > > What's about the atrf86230 driver?
> >
> > I couldn't find reliable information about what this meant:
> >
> > /* SUB:0 and BPSK:0 -> BPSK-20 */
> > /* SUB:1 and BPSK:0 -> BPSK-40 */
> > /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
> > /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
> >
> > None of these comments match the spec so I don't know what to put
> > there. If you know what these protocols are, I will immediately
> > provide this information into the driver and ensure the core handles
> > these durations properly before dropping the symbol_durations settings
> > from the code.
>
> I think those are from the transceiver datasheets (which are free to
> access). Can you not simply merge them or is there a conflict?
Actually I misread the driver, it supports several kind of chips with
different channel settings and this disturbed me. I downloaded the
datasheet and figured that the number after the protocol is the bit
rate. This helped me to make the connection with what I already know,
so both atusb and atrf86230 drivers have been converted too.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Thu, 13 Jan 2022 20:00:53 -0500:
> Hi,
>
> On Thu, 13 Jan 2022 at 04:30, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Wed, 12 Jan 2022 17:48:59 -0500:
> >
> > > Hi,
> > >
> > > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > The Cascada 8210 hardware transceiver is kind of a hardMAC which
> > > > interfaces with the softMAC and in practice does not support sending
> > > > anything else than dataframes. This means we cannot send any BEACON_REQ
> > > > during active scans nor any BEACON in general. Refuse these operations
> > > > officially so that the user is aware of the limitation.
> > > >
> > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > ---
> > > > drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> > > > 1 file changed, 24 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > index d3a9e4fe05f4..49c274280e3c 100644
> > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> > > > return link_to_linux_err(status);
> > > > }
> > > >
> > > > +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> > > > + struct cfg802154_scan_request *request)
> > > > +{
> > > > + /* This xceiver can only send dataframes */
> > > > + if (request->type != NL802154_SCAN_PASSIVE)
> > > > + return -EOPNOTSUPP;
> > > > +
> > > > + return 0;
> > > > +}
> > > > +
> > > > +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> > > > + struct cfg802154_beacons_request *request)
> > > > +{
> > > > + /* This xceiver can only send dataframes */
> > > > + return -EOPNOTSUPP;
> > > > +}
> > > > +
> > > > +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> > > > +
> > > > static const struct ieee802154_ops ca8210_phy_ops = {
> > > > .start = ca8210_start,
> > > > .stop = ca8210_stop,
> > > > @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> > > > .set_cca_ed_level = ca8210_set_cca_ed_level,
> > > > .set_csma_params = ca8210_set_csma_params,
> > > > .set_frame_retries = ca8210_set_frame_retries,
> > > > - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> > > > + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> > > > + .enter_scan_mode = ca8210_enter_scan_mode,
> > > > + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> > > > + .enter_beacons_mode = ca8210_enter_beacons_mode,
> > > > + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> > > > };
> > >
> > > so there is no flag that this driver can't support scanning currently
> > > and it works now because the offload functionality will return
> > > -ENOTSUPP? This is misleading because I would assume if it's not
> > > supported we can do it by software which the driver can't do.
> >
> > I believe there is a misunderstanding.
> >
> > This is what I have understood from your previous comments in v1:
> > "This driver does not support transmitting anything else than
> > datagrams", which is what I assumed was a regular data packet. IOW,
> > sending a MAC_CMD such as a beacon request or sending a beacon was not
> > supported physically by the hardware. Hence, most of the scans
> > operations cannot be performed and must be rejected (all but a passive
> > scan, assuming that receiving beacons was okay).
> >
>
> and I said that this driver is a HardMAC transceiver connected to the
> SoftMAC layer which is already wrong to exist (very special handling
> is required here).
> dataframes here are "data" type frames and I suppose it's also not
> able to deliver/receive other types than data to mac802154.
>
> It seems the author of this driver is happy to have data frames only
> but we need to take care that additional mac802154 handling is simply
> not possible to do here.
>
> > Please mind the update in that hook which currently is just an FYI from
> > the mac to the drivers and not a "do it by yourself" injunction. So
> > answering -EOPNOTSUPP to the mac here does not mean:
> > "I cannot handle it by myself, the scan cannot happen"
> > but
> > "I cannot handle the forged frames, so let's just not try"
> >
>
> The problem here is that a SoftMAC transceiver should always be
> capable of doing it by software so the "but case" makes no sense in
> this layer.
> On a mac802154 layer and "offload" driver functions as they are and
> they report me "-ENOTSUPP", I would assume that I can go back and do
> it by software which again should always be possible to do in
> mac802154.
>
> > > ... I see that the offload functions now are getting used and have a
> > > reason to be upstream, but the use of it is wrong.
> >
> > As a personal matter of taste, I don't like flags when it comes to
> > something complex like supporting a specific operation. Just in the
> > scanning procedure there are 4 different actions and a driver might
> > support only a subset of these, which is totally fine but hard to
> > properly describe by well-named flags. Here the driver hooks say to
> > the driver which are interested "here is what is going to happen" and
> > then they can:
> > - ignore the details by just not implementing the hooks, let the mac do
> > its job, they will then transmit the relevant frames forged by the
> > mac
> > - eventually enter a specific mode internally for this operation, but
> > basically do the same as above, ie. transmitting the frames forged
> > by the mac
> > - refuse the operation by returning an error code if something cannot
> > be done
> >
> > I've experienced a number of situations in the MTD world and later with
> > IIO drivers where flags have been remodeled and reused in different
> > manners, until the flag description gets totally wrong and
> > undescriptive regarding what it actually does. Hence my main idea of
> > letting drivers refuse these operations instead of having the mac doing
> > it for them.
> >
> > I can definitely use flags if you want, but in this case, what flags do
> > you want to see?
> >
>
> Do some phy quirks flags which indicate that the transceiver is not
> capable of doing scan operation by software. Or just use a boolean in
> phy capabilities (but don't export them to userspace, note that this
> flag should be removed later) if this operation is not allowed.
I've added a phy flag to distinguish this driver as early as possible.
>
> I don't like this flag either, it is a workaround to still support the
> driver as it is and don't allow new fancy things because it cannot
> handle it. We should work on it to remove this flag, but this is a
> longer process. Either the driver is implementing those hooks "real"
> to somehow run a scan (but at it's own risk) or it needs to be
> implemented as a HardMAC driver. This driver is already difficult to
> maintain because it doesn't fit here...
>
> - Alex
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Thu, 13 Jan 2022 19:01:56 -0500:
> Hi,
>
> On Thu, 13 Jan 2022 at 12:07, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
> >
> > > Hi,
> > >
> > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > ...
> > > > + return 0;
> > > > +}
> > > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > > > index c829e4a75325..40656728c624 100644
> > > > --- a/net/mac802154/tx.c
> > > > +++ b/net/mac802154/tx.c
> > > > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > > > struct net_device *dev = skb->dev;
> > > > int ret;
> > > >
> > > > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > > > + return NETDEV_TX_BUSY;
> > > > +
> > >
> > > Please look into the functions "ieee802154_wake_queue()" and
> > > "ieee802154_stop_queue()" which prevent this function from being
> > > called. Call stop before starting scanning and wake after scanning is
> > > done or stopped.
> >
> > Mmmh all this is already done, isn't it?
> > - mac802154_trigger_scan_locked() stops the queue before setting the
> > promiscuous mode
> > - mac802154_end_of_scan() wakes the queue after resetting the
> > promiscuous mode to its original state
> >
> > Should I drop the check which stands for an extra precaution?
> >
>
> no, I think then it should be a WARN_ON() more without any return
> (hopefully it will survive). This case should never happen otherwise
> we have a bug that we wake the queue when we "took control about
> transmissions" only.
> Change the name, I think it will be in future not only scan related.
> Maybe "mac802154_queue_stopped()". Everything which is queued from
> socket/upperlayer(6lowpan) goes this way.
Got it.
I've changed the name of the helper, and used an atomic variable there
to follow the count.
> > But overall I think I don't understand well this part. What is
> > a bit foggy to me is why the (async) tx implementation does:
> >
> > *Core* *Driver*
> >
> > stop_queue()
> > drv_async_xmit() -------
> > \------> do something
> > ------- calls ieee802154_xmit_complete()
> > wakeup_queue() <--------/
> >
> > So we actually disable the queue for transmitting. Why??
> >
>
> Because all transceivers have either _one_ transmit framebuffer or one
> framebuffer for transmit and receive one time. We need to report to
> stop giving us more skb's while we are busy with one to transmit.
> This all will/must be changed in future if there is hardware outside
> which is more powerful and the driver needs to control the flow here.
>
> That ieee802154_xmit_complete() calls wakeup_queue need to be
> forbidden when we are in "synchronous transmit mode"/the queue is
> stopped. The synchronous transmit mode is not for any hotpath, it's
> for MLME and I think we also need a per phy lock to avoid multiple
> synchronous transmissions at one time. Please note that I don't think
> here only about scan operation, also for other possible MLME-ops.
>
First, thank you very much for all your guidance and reviews, I think I
have a much clearer understanding now.
I've tried to follow your advices, creating:
- a way of tracking ongoing transmissions
- a synchronous API for MLME transfers
I've decided to use the wait_queue + atomic combo which looks nice.
Everything seems to work, I just need a bit of time to clean and rework
a bit the series before sending a v3.
Thanks,
Miquèl
Hi,
On Fri, 14 Jan 2022 at 13:44, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Thu, 13 Jan 2022 19:01:56 -0500:
>
> > Hi,
> >
> > On Thu, 13 Jan 2022 at 12:07, Miquel Raynal <[email protected]> wrote:
> > >
> > > Hi Alexander,
> > >
> > > [email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
> > >
> > > > Hi,
> > > >
> > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > ...
> > > > > + return 0;
> > > > > +}
> > > > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > > > > index c829e4a75325..40656728c624 100644
> > > > > --- a/net/mac802154/tx.c
> > > > > +++ b/net/mac802154/tx.c
> > > > > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > > > > struct net_device *dev = skb->dev;
> > > > > int ret;
> > > > >
> > > > > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > > > > + return NETDEV_TX_BUSY;
> > > > > +
> > > >
> > > > Please look into the functions "ieee802154_wake_queue()" and
> > > > "ieee802154_stop_queue()" which prevent this function from being
> > > > called. Call stop before starting scanning and wake after scanning is
> > > > done or stopped.
> > >
> > > Mmmh all this is already done, isn't it?
> > > - mac802154_trigger_scan_locked() stops the queue before setting the
> > > promiscuous mode
> > > - mac802154_end_of_scan() wakes the queue after resetting the
> > > promiscuous mode to its original state
> > >
> > > Should I drop the check which stands for an extra precaution?
> > >
> >
> > no, I think then it should be a WARN_ON() more without any return
> > (hopefully it will survive). This case should never happen otherwise
> > we have a bug that we wake the queue when we "took control about
> > transmissions" only.
> > Change the name, I think it will be in future not only scan related.
> > Maybe "mac802154_queue_stopped()". Everything which is queued from
> > socket/upperlayer(6lowpan) goes this way.
>
> Got it.
>
> I've changed the name of the helper, and used an atomic variable there
> to follow the count.
>
> > > But overall I think I don't understand well this part. What is
> > > a bit foggy to me is why the (async) tx implementation does:
> > >
> > > *Core* *Driver*
> > >
> > > stop_queue()
> > > drv_async_xmit() -------
> > > \------> do something
> > > ------- calls ieee802154_xmit_complete()
> > > wakeup_queue() <--------/
> > >
> > > So we actually disable the queue for transmitting. Why??
> > >
> >
> > Because all transceivers have either _one_ transmit framebuffer or one
> > framebuffer for transmit and receive one time. We need to report to
> > stop giving us more skb's while we are busy with one to transmit.
> > This all will/must be changed in future if there is hardware outside
> > which is more powerful and the driver needs to control the flow here.
> >
> > That ieee802154_xmit_complete() calls wakeup_queue need to be
> > forbidden when we are in "synchronous transmit mode"/the queue is
> > stopped. The synchronous transmit mode is not for any hotpath, it's
> > for MLME and I think we also need a per phy lock to avoid multiple
> > synchronous transmissions at one time. Please note that I don't think
> > here only about scan operation, also for other possible MLME-ops.
> >
>
> First, thank you very much for all your guidance and reviews, I think I
> have a much clearer understanding now.
>
> I've tried to follow your advices, creating:
> - a way of tracking ongoing transmissions
> - a synchronous API for MLME transfers
>
Please note that I think we cannot use netif_stop_queue() from context
outside of netif xmit() callback. It's because the atomic counter
itself is racy in xmit(), we need to be sure xmit() can't occur while
stopping the queue. I think maybe "netif_tx_disable()" is the right
call to stop from another context, because it holds the tx_lock, which
I believe is held while xmit().
Where the wake queue call should be fine to call..., maybe we can
remove some EXPORT_SYMBOL() then?
I saw that some drivers call "ieee802154_wake_queue()" in error cases,
may we introduce a new helper "?ieee802154_xmit_error?" for error
cases so you can also catch error cases in your sync tx. See `grep -r
"ieee802154_wake_queue" drivers/net/ieee802154`, if we have more
information we might add more meaning into the error cases (e.g.
proper errno).
> I've decided to use the wait_queue + atomic combo which looks nice.
> Everything seems to work, I just need a bit of time to clean and rework
> a bit the series before sending a v3.
>
Okay, sounds good to implement both requirements.
- Alex
Hi,
On Fri, 14 Jan 2022 at 13:37, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Thu, 13 Jan 2022 20:00:53 -0500:
>
> > Hi,
> >
> > On Thu, 13 Jan 2022 at 04:30, Miquel Raynal <[email protected]> wrote:
> > >
> > > Hi Alexander,
> > >
> > > [email protected] wrote on Wed, 12 Jan 2022 17:48:59 -0500:
> > >
> > > > Hi,
> > > >
> > > > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > > > >
> > > > > The Cascada 8210 hardware transceiver is kind of a hardMAC which
> > > > > interfaces with the softMAC and in practice does not support sending
> > > > > anything else than dataframes. This means we cannot send any BEACON_REQ
> > > > > during active scans nor any BEACON in general. Refuse these operations
> > > > > officially so that the user is aware of the limitation.
> > > > >
> > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > ---
> > > > > drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> > > > > 1 file changed, 24 insertions(+), 1 deletion(-)
> > > > >
> > > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > > index d3a9e4fe05f4..49c274280e3c 100644
> > > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > > @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> > > > > return link_to_linux_err(status);
> > > > > }
> > > > >
> > > > > +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> > > > > + struct cfg802154_scan_request *request)
> > > > > +{
> > > > > + /* This xceiver can only send dataframes */
> > > > > + if (request->type != NL802154_SCAN_PASSIVE)
> > > > > + return -EOPNOTSUPP;
> > > > > +
> > > > > + return 0;
> > > > > +}
> > > > > +
> > > > > +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> > > > > + struct cfg802154_beacons_request *request)
> > > > > +{
> > > > > + /* This xceiver can only send dataframes */
> > > > > + return -EOPNOTSUPP;
> > > > > +}
> > > > > +
> > > > > +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> > > > > +
> > > > > static const struct ieee802154_ops ca8210_phy_ops = {
> > > > > .start = ca8210_start,
> > > > > .stop = ca8210_stop,
> > > > > @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> > > > > .set_cca_ed_level = ca8210_set_cca_ed_level,
> > > > > .set_csma_params = ca8210_set_csma_params,
> > > > > .set_frame_retries = ca8210_set_frame_retries,
> > > > > - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> > > > > + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> > > > > + .enter_scan_mode = ca8210_enter_scan_mode,
> > > > > + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> > > > > + .enter_beacons_mode = ca8210_enter_beacons_mode,
> > > > > + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> > > > > };
> > > >
> > > > so there is no flag that this driver can't support scanning currently
> > > > and it works now because the offload functionality will return
> > > > -ENOTSUPP? This is misleading because I would assume if it's not
> > > > supported we can do it by software which the driver can't do.
> > >
> > > I believe there is a misunderstanding.
> > >
> > > This is what I have understood from your previous comments in v1:
> > > "This driver does not support transmitting anything else than
> > > datagrams", which is what I assumed was a regular data packet. IOW,
> > > sending a MAC_CMD such as a beacon request or sending a beacon was not
> > > supported physically by the hardware. Hence, most of the scans
> > > operations cannot be performed and must be rejected (all but a passive
> > > scan, assuming that receiving beacons was okay).
> > >
> >
> > and I said that this driver is a HardMAC transceiver connected to the
> > SoftMAC layer which is already wrong to exist (very special handling
> > is required here).
> > dataframes here are "data" type frames and I suppose it's also not
> > able to deliver/receive other types than data to mac802154.
> >
> > It seems the author of this driver is happy to have data frames only
> > but we need to take care that additional mac802154 handling is simply
> > not possible to do here.
> >
> > > Please mind the update in that hook which currently is just an FYI from
> > > the mac to the drivers and not a "do it by yourself" injunction. So
> > > answering -EOPNOTSUPP to the mac here does not mean:
> > > "I cannot handle it by myself, the scan cannot happen"
> > > but
> > > "I cannot handle the forged frames, so let's just not try"
> > >
> >
> > The problem here is that a SoftMAC transceiver should always be
> > capable of doing it by software so the "but case" makes no sense in
> > this layer.
> > On a mac802154 layer and "offload" driver functions as they are and
> > they report me "-ENOTSUPP", I would assume that I can go back and do
> > it by software which again should always be possible to do in
> > mac802154.
> >
> > > > ... I see that the offload functions now are getting used and have a
> > > > reason to be upstream, but the use of it is wrong.
> > >
> > > As a personal matter of taste, I don't like flags when it comes to
> > > something complex like supporting a specific operation. Just in the
> > > scanning procedure there are 4 different actions and a driver might
> > > support only a subset of these, which is totally fine but hard to
> > > properly describe by well-named flags. Here the driver hooks say to
> > > the driver which are interested "here is what is going to happen" and
> > > then they can:
> > > - ignore the details by just not implementing the hooks, let the mac do
> > > its job, they will then transmit the relevant frames forged by the
> > > mac
> > > - eventually enter a specific mode internally for this operation, but
> > > basically do the same as above, ie. transmitting the frames forged
> > > by the mac
> > > - refuse the operation by returning an error code if something cannot
> > > be done
> > >
> > > I've experienced a number of situations in the MTD world and later with
> > > IIO drivers where flags have been remodeled and reused in different
> > > manners, until the flag description gets totally wrong and
> > > undescriptive regarding what it actually does. Hence my main idea of
> > > letting drivers refuse these operations instead of having the mac doing
> > > it for them.
> > >
> > > I can definitely use flags if you want, but in this case, what flags do
> > > you want to see?
> > >
> >
> > Do some phy quirks flags which indicate that the transceiver is not
> > capable of doing scan operation by software. Or just use a boolean in
> > phy capabilities (but don't export them to userspace, note that this
> > flag should be removed later) if this operation is not allowed.
>
> I've added a phy flag to distinguish this driver as early as possible.
I was thinking about this a lot and I think the driver is already
buggy in many ways e.g. what happens when we do AF_PACKET raw sockets
and do some different frame types than data. I have no idea, maybe we
should leave it as it is... and simply don't care? Maybe the driver
needs to drop a lot of frames if they are different... it runs already
different than other transceivers which we don't check at all.
- Alex
Hi,
On Sun, 16 Jan 2022 at 17:44, Alexander Aring <[email protected]> wrote:
>
> Hi,
>
> On Fri, 14 Jan 2022 at 13:44, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Thu, 13 Jan 2022 19:01:56 -0500:
> >
> > > Hi,
> > >
> > > On Thu, 13 Jan 2022 at 12:07, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > Hi Alexander,
> > > >
> > > > [email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
> > > >
> > > > > Hi,
> > > > >
> > > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > > ...
> > > > > > + return 0;
> > > > > > +}
> > > > > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > > > > > index c829e4a75325..40656728c624 100644
> > > > > > --- a/net/mac802154/tx.c
> > > > > > +++ b/net/mac802154/tx.c
> > > > > > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > > > > > struct net_device *dev = skb->dev;
> > > > > > int ret;
> > > > > >
> > > > > > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > > > > > + return NETDEV_TX_BUSY;
> > > > > > +
> > > > >
> > > > > Please look into the functions "ieee802154_wake_queue()" and
> > > > > "ieee802154_stop_queue()" which prevent this function from being
> > > > > called. Call stop before starting scanning and wake after scanning is
> > > > > done or stopped.
> > > >
> > > > Mmmh all this is already done, isn't it?
> > > > - mac802154_trigger_scan_locked() stops the queue before setting the
> > > > promiscuous mode
> > > > - mac802154_end_of_scan() wakes the queue after resetting the
> > > > promiscuous mode to its original state
> > > >
> > > > Should I drop the check which stands for an extra precaution?
> > > >
> > >
> > > no, I think then it should be a WARN_ON() more without any return
> > > (hopefully it will survive). This case should never happen otherwise
> > > we have a bug that we wake the queue when we "took control about
> > > transmissions" only.
> > > Change the name, I think it will be in future not only scan related.
> > > Maybe "mac802154_queue_stopped()". Everything which is queued from
> > > socket/upperlayer(6lowpan) goes this way.
> >
> > Got it.
> >
> > I've changed the name of the helper, and used an atomic variable there
> > to follow the count.
> >
> > > > But overall I think I don't understand well this part. What is
> > > > a bit foggy to me is why the (async) tx implementation does:
> > > >
> > > > *Core* *Driver*
> > > >
> > > > stop_queue()
> > > > drv_async_xmit() -------
> > > > \------> do something
> > > > ------- calls ieee802154_xmit_complete()
> > > > wakeup_queue() <--------/
> > > >
> > > > So we actually disable the queue for transmitting. Why??
> > > >
> > >
> > > Because all transceivers have either _one_ transmit framebuffer or one
> > > framebuffer for transmit and receive one time. We need to report to
> > > stop giving us more skb's while we are busy with one to transmit.
> > > This all will/must be changed in future if there is hardware outside
> > > which is more powerful and the driver needs to control the flow here.
> > >
> > > That ieee802154_xmit_complete() calls wakeup_queue need to be
> > > forbidden when we are in "synchronous transmit mode"/the queue is
> > > stopped. The synchronous transmit mode is not for any hotpath, it's
> > > for MLME and I think we also need a per phy lock to avoid multiple
> > > synchronous transmissions at one time. Please note that I don't think
> > > here only about scan operation, also for other possible MLME-ops.
> > >
> >
> > First, thank you very much for all your guidance and reviews, I think I
> > have a much clearer understanding now.
> >
> > I've tried to follow your advices, creating:
> > - a way of tracking ongoing transmissions
> > - a synchronous API for MLME transfers
> >
>
> Please note that I think we cannot use netif_stop_queue() from context
> outside of netif xmit() callback. It's because the atomic counter
> itself is racy in xmit(), we need to be sure xmit() can't occur while
> stopping the queue. I think maybe "netif_tx_disable()" is the right
> call to stop from another context, because it holds the tx_lock, which
> I believe is held while xmit().
> Where the wake queue call should be fine to call..., maybe we can
> remove some EXPORT_SYMBOL() then?
>
I am sorry, that comment should go below.
> I saw that some drivers call "ieee802154_wake_queue()" in error cases,
> may we introduce a new helper "?ieee802154_xmit_error?" for error
> cases so you can also catch error cases in your sync tx. See `grep -r
> "ieee802154_wake_queue" drivers/net/ieee802154`, if we have more
> information we might add more meaning into the error cases (e.g.
> proper errno).
maybe we can remove some EXPORT_SYMBOL() then?
- Alex
Hi,
On Fri, 14 Jan 2022 at 05:21, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Thu, 13 Jan 2022 18:34:00 -0500:
>
> > Hi,
> >
> > On Thu, 13 Jan 2022 at 06:16, Miquel Raynal <[email protected]> wrote:
> > >
> > > Hi Alexander,
> > >
> > > [email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
> > >
> > > > Hi,
> > > >
> > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > >
> > > > > The core now knows how to set the symbol duration in a few cases, when
> > > > > drivers correctly advertise the protocols used on each channel. For
> > > > > these drivers, there is no more need to bother with symbol duration, so
> > > > > just drop the duplicated code.
> > > > >
> > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > ---
> > > > > drivers/net/ieee802154/ca8210.c | 1 -
> > > > > drivers/net/ieee802154/mcr20a.c | 2 --
> > > > > 2 files changed, 3 deletions(-)
> > > > >
> > > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > > > > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > > > > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > > > > ca8210_hw->phy->cca_ed_level = -9800;
> > > > > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > > > > ca8210_hw->phy->lifs_period = 40;
> > > > > ca8210_hw->phy->sifs_period = 12;
> > > > > ca8210_hw->flags =
> > > > > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > > > > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > > > > --- a/drivers/net/ieee802154/mcr20a.c
> > > > > +++ b/drivers/net/ieee802154/mcr20a.c
> > > > > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > >
> > > > > dev_dbg(printdev(lp), "%s\n", __func__);
> > > > >
> > > > > - phy->symbol_duration = 16 * 1000;
> > > > > phy->lifs_period = 40;
> > > > > phy->sifs_period = 12;
> > > > >
> > > > > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > > phy->current_page = 0;
> > > > > /* MCR20A default reset value */
> > > > > phy->current_channel = 20;
> > > > > - phy->symbol_duration = 16 * 1000;
> > > > > phy->supported.tx_powers = mcr20a_powers;
> > > > > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > > > > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
> > > >
> > > > What's about the atrf86230 driver?
> > >
> > > I couldn't find reliable information about what this meant:
> > >
> > > /* SUB:0 and BPSK:0 -> BPSK-20 */
> > > /* SUB:1 and BPSK:0 -> BPSK-40 */
> > > /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
> > > /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
> > >
> > > None of these comments match the spec so I don't know what to put
> > > there. If you know what these protocols are, I will immediately
> > > provide this information into the driver and ensure the core handles
> > > these durations properly before dropping the symbol_durations settings
> > > from the code.
> >
> > I think those are from the transceiver datasheets (which are free to
> > access). Can you not simply merge them or is there a conflict?
>
> Actually I misread the driver, it supports several kind of chips with
> different channel settings and this disturbed me. I downloaded the
> datasheet and figured that the number after the protocol is the bit
> rate. This helped me to make the connection with what I already know,
> so both atusb and atrf86230 drivers have been converted too.
and what is about hwsim? I think the table gets too large then...
that's why I was thinking of moving that somehow to the regdb, however
this is another project as I said and this way is fine. Maybe we use a
kind of fallback then? The hwsim phy isn't really any 802.15.4 PHY,
it's just memcpy() but it would be nice to be able to test scan with
it. So far I understand it is already possible to make something with
hwsim here but what about the zero symbol rate and the "waiting
period" is zero?
btw:
Also for testing with hwsim and the missing features which currently
exist. Can we implement some user space test program which replies
(active scan) or sends periodically something out via AF_PACKET raw
and a monitor interface that should work to test if it is working?
Ideally we could do that very easily with scapy (not sure about their
_upstream_ 802.15.4 support). I hope I got that right that there is
still something missing but we could fake it in such a way (just for
hwsim testing).
Side note: tx via monitor over AF_PACKET raw is without fcs currently.
- Alex
Hi Alexander,
[email protected] wrote on Sun, 16 Jan 2022 17:44:18 -0500:
> Hi,
>
> On Fri, 14 Jan 2022 at 13:44, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Thu, 13 Jan 2022 19:01:56 -0500:
> >
> > > Hi,
> > >
> > > On Thu, 13 Jan 2022 at 12:07, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > Hi Alexander,
> > > >
> > > > [email protected] wrote on Wed, 12 Jan 2022 17:44:02 -0500:
> > > >
> > > > > Hi,
> > > > >
> > > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > > ...
> > > > > > + return 0;
> > > > > > +}
> > > > > > diff --git a/net/mac802154/tx.c b/net/mac802154/tx.c
> > > > > > index c829e4a75325..40656728c624 100644
> > > > > > --- a/net/mac802154/tx.c
> > > > > > +++ b/net/mac802154/tx.c
> > > > > > @@ -54,6 +54,9 @@ ieee802154_tx(struct ieee802154_local *local, struct sk_buff *skb)
> > > > > > struct net_device *dev = skb->dev;
> > > > > > int ret;
> > > > > >
> > > > > > + if (unlikely(mac802154_scan_is_ongoing(local)))
> > > > > > + return NETDEV_TX_BUSY;
> > > > > > +
> > > > >
> > > > > Please look into the functions "ieee802154_wake_queue()" and
> > > > > "ieee802154_stop_queue()" which prevent this function from being
> > > > > called. Call stop before starting scanning and wake after scanning is
> > > > > done or stopped.
> > > >
> > > > Mmmh all this is already done, isn't it?
> > > > - mac802154_trigger_scan_locked() stops the queue before setting the
> > > > promiscuous mode
> > > > - mac802154_end_of_scan() wakes the queue after resetting the
> > > > promiscuous mode to its original state
> > > >
> > > > Should I drop the check which stands for an extra precaution?
> > > >
> > >
> > > no, I think then it should be a WARN_ON() more without any return
> > > (hopefully it will survive). This case should never happen otherwise
> > > we have a bug that we wake the queue when we "took control about
> > > transmissions" only.
> > > Change the name, I think it will be in future not only scan related.
> > > Maybe "mac802154_queue_stopped()". Everything which is queued from
> > > socket/upperlayer(6lowpan) goes this way.
> >
> > Got it.
> >
> > I've changed the name of the helper, and used an atomic variable there
> > to follow the count.
> >
> > > > But overall I think I don't understand well this part. What is
> > > > a bit foggy to me is why the (async) tx implementation does:
> > > >
> > > > *Core* *Driver*
> > > >
> > > > stop_queue()
> > > > drv_async_xmit() -------
> > > > \------> do something
> > > > ------- calls ieee802154_xmit_complete()
> > > > wakeup_queue() <--------/
> > > >
> > > > So we actually disable the queue for transmitting. Why??
> > > >
> > >
> > > Because all transceivers have either _one_ transmit framebuffer or one
> > > framebuffer for transmit and receive one time. We need to report to
> > > stop giving us more skb's while we are busy with one to transmit.
> > > This all will/must be changed in future if there is hardware outside
> > > which is more powerful and the driver needs to control the flow here.
> > >
> > > That ieee802154_xmit_complete() calls wakeup_queue need to be
> > > forbidden when we are in "synchronous transmit mode"/the queue is
> > > stopped. The synchronous transmit mode is not for any hotpath, it's
> > > for MLME and I think we also need a per phy lock to avoid multiple
> > > synchronous transmissions at one time. Please note that I don't think
> > > here only about scan operation, also for other possible MLME-ops.
> > >
> >
> > First, thank you very much for all your guidance and reviews, I think I
> > have a much clearer understanding now.
> >
> > I've tried to follow your advices, creating:
> > - a way of tracking ongoing transmissions
> > - a synchronous API for MLME transfers
> >
>
> Please note that I think we cannot use netif_stop_queue() from context
> outside of netif xmit() callback. It's because the atomic counter
> itself is racy in xmit(), we need to be sure xmit() can't occur while
> stopping the queue.
In my current implementation I don't see this as a real problem because
for me, there is no real difference between:
- a transfer is started
- we call stop_queue()
* right here a transfer is ongoing *
and
- we call stop_queue()
- the counter is racy hence a last transfer is started
* right here a transfer is ongoing *
because stopping the queue and "flushing" it are two different things.
In the code I don't only rely on the queue being stopped but if I don't
want any more transfer to happen after that, so I also sync the queue
thanks to the new helpers introduced.
Please check v3 (which is coming very soon) and tell me what you think.
Maybe I missed something.
> I think maybe "netif_tx_disable()" is the right
> call to stop from another context, because it holds the tx_lock, which
> I believe is held while xmit().
> Where the wake queue call should be fine to call..., maybe we can
> remove some EXPORT_SYMBOL() then?
>
> I saw that some drivers call "ieee802154_wake_queue()" in error cases,
> may we introduce a new helper "?ieee802154_xmit_error?" for error
> cases so you can also catch error cases in your sync tx. See `grep -r
> "ieee802154_wake_queue" drivers/net/ieee802154`, if we have more
> information we might add more meaning into the error cases (e.g.
> proper errno).
Most of the time the calling functions are void functions. In fact they
all simply hardcode the xmit_done helper and even worse, sometimes they
simply leak the skb. I've handled that already by updating all these
callers to be sure the only way out is to call xmit_done, which helps a
lot tracking transfers.
Also, you are right, we can certainly drop a couple of EXPORT_SYMBOLS
:-)
> > I've decided to use the wait_queue + atomic combo which looks nice.
> > Everything seems to work, I just need a bit of time to clean and rework
> > a bit the series before sending a v3.
> >
>
> Okay, sounds good to implement both requirements.
>
> - Alex
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Sun, 16 Jan 2022 17:48:03 -0500:
> Hi,
>
> On Fri, 14 Jan 2022 at 13:37, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Thu, 13 Jan 2022 20:00:53 -0500:
> >
> > > Hi,
> > >
> > > On Thu, 13 Jan 2022 at 04:30, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > Hi Alexander,
> > > >
> > > > [email protected] wrote on Wed, 12 Jan 2022 17:48:59 -0500:
> > > >
> > > > > Hi,
> > > > >
> > > > > On Wed, 12 Jan 2022 at 12:34, Miquel Raynal <[email protected]> wrote:
> > > > > >
> > > > > > The Cascada 8210 hardware transceiver is kind of a hardMAC which
> > > > > > interfaces with the softMAC and in practice does not support sending
> > > > > > anything else than dataframes. This means we cannot send any BEACON_REQ
> > > > > > during active scans nor any BEACON in general. Refuse these operations
> > > > > > officially so that the user is aware of the limitation.
> > > > > >
> > > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > > ---
> > > > > > drivers/net/ieee802154/ca8210.c | 25 ++++++++++++++++++++++++-
> > > > > > 1 file changed, 24 insertions(+), 1 deletion(-)
> > > > > >
> > > > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > > > index d3a9e4fe05f4..49c274280e3c 100644
> > > > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > > > @@ -2385,6 +2385,25 @@ static int ca8210_set_promiscuous_mode(struct ieee802154_hw *hw, const bool on)
> > > > > > return link_to_linux_err(status);
> > > > > > }
> > > > > >
> > > > > > +static int ca8210_enter_scan_mode(struct ieee802154_hw *hw,
> > > > > > + struct cfg802154_scan_request *request)
> > > > > > +{
> > > > > > + /* This xceiver can only send dataframes */
> > > > > > + if (request->type != NL802154_SCAN_PASSIVE)
> > > > > > + return -EOPNOTSUPP;
> > > > > > +
> > > > > > + return 0;
> > > > > > +}
> > > > > > +
> > > > > > +static int ca8210_enter_beacons_mode(struct ieee802154_hw *hw,
> > > > > > + struct cfg802154_beacons_request *request)
> > > > > > +{
> > > > > > + /* This xceiver can only send dataframes */
> > > > > > + return -EOPNOTSUPP;
> > > > > > +}
> > > > > > +
> > > > > > +static void ca8210_exit_scan_beacons_mode(struct ieee802154_hw *hw) { }
> > > > > > +
> > > > > > static const struct ieee802154_ops ca8210_phy_ops = {
> > > > > > .start = ca8210_start,
> > > > > > .stop = ca8210_stop,
> > > > > > @@ -2397,7 +2416,11 @@ static const struct ieee802154_ops ca8210_phy_ops = {
> > > > > > .set_cca_ed_level = ca8210_set_cca_ed_level,
> > > > > > .set_csma_params = ca8210_set_csma_params,
> > > > > > .set_frame_retries = ca8210_set_frame_retries,
> > > > > > - .set_promiscuous_mode = ca8210_set_promiscuous_mode
> > > > > > + .set_promiscuous_mode = ca8210_set_promiscuous_mode,
> > > > > > + .enter_scan_mode = ca8210_enter_scan_mode,
> > > > > > + .exit_scan_mode = ca8210_exit_scan_beacons_mode,
> > > > > > + .enter_beacons_mode = ca8210_enter_beacons_mode,
> > > > > > + .exit_beacons_mode = ca8210_exit_scan_beacons_mode,
> > > > > > };
> > > > >
> > > > > so there is no flag that this driver can't support scanning currently
> > > > > and it works now because the offload functionality will return
> > > > > -ENOTSUPP? This is misleading because I would assume if it's not
> > > > > supported we can do it by software which the driver can't do.
> > > >
> > > > I believe there is a misunderstanding.
> > > >
> > > > This is what I have understood from your previous comments in v1:
> > > > "This driver does not support transmitting anything else than
> > > > datagrams", which is what I assumed was a regular data packet. IOW,
> > > > sending a MAC_CMD such as a beacon request or sending a beacon was not
> > > > supported physically by the hardware. Hence, most of the scans
> > > > operations cannot be performed and must be rejected (all but a passive
> > > > scan, assuming that receiving beacons was okay).
> > > >
> > >
> > > and I said that this driver is a HardMAC transceiver connected to the
> > > SoftMAC layer which is already wrong to exist (very special handling
> > > is required here).
> > > dataframes here are "data" type frames and I suppose it's also not
> > > able to deliver/receive other types than data to mac802154.
> > >
> > > It seems the author of this driver is happy to have data frames only
> > > but we need to take care that additional mac802154 handling is simply
> > > not possible to do here.
> > >
> > > > Please mind the update in that hook which currently is just an FYI from
> > > > the mac to the drivers and not a "do it by yourself" injunction. So
> > > > answering -EOPNOTSUPP to the mac here does not mean:
> > > > "I cannot handle it by myself, the scan cannot happen"
> > > > but
> > > > "I cannot handle the forged frames, so let's just not try"
> > > >
> > >
> > > The problem here is that a SoftMAC transceiver should always be
> > > capable of doing it by software so the "but case" makes no sense in
> > > this layer.
> > > On a mac802154 layer and "offload" driver functions as they are and
> > > they report me "-ENOTSUPP", I would assume that I can go back and do
> > > it by software which again should always be possible to do in
> > > mac802154.
> > >
> > > > > ... I see that the offload functions now are getting used and have a
> > > > > reason to be upstream, but the use of it is wrong.
> > > >
> > > > As a personal matter of taste, I don't like flags when it comes to
> > > > something complex like supporting a specific operation. Just in the
> > > > scanning procedure there are 4 different actions and a driver might
> > > > support only a subset of these, which is totally fine but hard to
> > > > properly describe by well-named flags. Here the driver hooks say to
> > > > the driver which are interested "here is what is going to happen" and
> > > > then they can:
> > > > - ignore the details by just not implementing the hooks, let the mac do
> > > > its job, they will then transmit the relevant frames forged by the
> > > > mac
> > > > - eventually enter a specific mode internally for this operation, but
> > > > basically do the same as above, ie. transmitting the frames forged
> > > > by the mac
> > > > - refuse the operation by returning an error code if something cannot
> > > > be done
> > > >
> > > > I've experienced a number of situations in the MTD world and later with
> > > > IIO drivers where flags have been remodeled and reused in different
> > > > manners, until the flag description gets totally wrong and
> > > > undescriptive regarding what it actually does. Hence my main idea of
> > > > letting drivers refuse these operations instead of having the mac doing
> > > > it for them.
> > > >
> > > > I can definitely use flags if you want, but in this case, what flags do
> > > > you want to see?
> > > >
> > >
> > > Do some phy quirks flags which indicate that the transceiver is not
> > > capable of doing scan operation by software. Or just use a boolean in
> > > phy capabilities (but don't export them to userspace, note that this
> > > flag should be removed later) if this operation is not allowed.
> >
> > I've added a phy flag to distinguish this driver as early as possible.
>
> I was thinking about this a lot and I think the driver is already
> buggy in many ways e.g. what happens when we do AF_PACKET raw sockets
> and do some different frame types than data. I have no idea, maybe we
> should leave it as it is... and simply don't care? Maybe the driver
> needs to drop a lot of frames if they are different... it runs already
> different than other transceivers which we don't check at all.
For now I've handled it with a flag, I'll send the patch as it is so
that someone else can pick it up if you finally decide to not touch
this driver for now and change your mind later on.
I would however argue that having these constraint devices flagged in
some way is better than nothing. You personally know the issue, but
newcomers don't.
Thanks,
Miquèl
Hi Alexander,
[email protected] wrote on Sun, 16 Jan 2022 18:21:16 -0500:
> Hi,
>
> On Fri, 14 Jan 2022 at 05:21, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > [email protected] wrote on Thu, 13 Jan 2022 18:34:00 -0500:
> >
> > > Hi,
> > >
> > > On Thu, 13 Jan 2022 at 06:16, Miquel Raynal <[email protected]> wrote:
> > > >
> > > > Hi Alexander,
> > > >
> > > > [email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
> > > >
> > > > > Hi,
> > > > >
> > > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > > >
> > > > > > The core now knows how to set the symbol duration in a few cases, when
> > > > > > drivers correctly advertise the protocols used on each channel. For
> > > > > > these drivers, there is no more need to bother with symbol duration, so
> > > > > > just drop the duplicated code.
> > > > > >
> > > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > > ---
> > > > > > drivers/net/ieee802154/ca8210.c | 1 -
> > > > > > drivers/net/ieee802154/mcr20a.c | 2 --
> > > > > > 2 files changed, 3 deletions(-)
> > > > > >
> > > > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > > > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > > > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > > > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > > > > > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > > > > > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > > > > > ca8210_hw->phy->cca_ed_level = -9800;
> > > > > > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > > > > > ca8210_hw->phy->lifs_period = 40;
> > > > > > ca8210_hw->phy->sifs_period = 12;
> > > > > > ca8210_hw->flags =
> > > > > > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > > > > > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > > > > > --- a/drivers/net/ieee802154/mcr20a.c
> > > > > > +++ b/drivers/net/ieee802154/mcr20a.c
> > > > > > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > > >
> > > > > > dev_dbg(printdev(lp), "%s\n", __func__);
> > > > > >
> > > > > > - phy->symbol_duration = 16 * 1000;
> > > > > > phy->lifs_period = 40;
> > > > > > phy->sifs_period = 12;
> > > > > >
> > > > > > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > > > phy->current_page = 0;
> > > > > > /* MCR20A default reset value */
> > > > > > phy->current_channel = 20;
> > > > > > - phy->symbol_duration = 16 * 1000;
> > > > > > phy->supported.tx_powers = mcr20a_powers;
> > > > > > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > > > > > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
> > > > >
> > > > > What's about the atrf86230 driver?
> > > >
> > > > I couldn't find reliable information about what this meant:
> > > >
> > > > /* SUB:0 and BPSK:0 -> BPSK-20 */
> > > > /* SUB:1 and BPSK:0 -> BPSK-40 */
> > > > /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
> > > > /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
> > > >
> > > > None of these comments match the spec so I don't know what to put
> > > > there. If you know what these protocols are, I will immediately
> > > > provide this information into the driver and ensure the core handles
> > > > these durations properly before dropping the symbol_durations settings
> > > > from the code.
> > >
> > > I think those are from the transceiver datasheets (which are free to
> > > access). Can you not simply merge them or is there a conflict?
> >
> > Actually I misread the driver, it supports several kind of chips with
> > different channel settings and this disturbed me. I downloaded the
> > datasheet and figured that the number after the protocol is the bit
> > rate. This helped me to make the connection with what I already know,
> > so both atusb and atrf86230 drivers have been converted too.
>
> and what is about hwsim? I think the table gets too large then...
I'm sorry but I don't follow you here, what do you mean by "the table
gets too large"?
> that's why I was thinking of moving that somehow to the regdb, however
> this is another project as I said and this way is fine. Maybe we use a
> kind of fallback then? The hwsim phy isn't really any 802.15.4 PHY,
> it's just memcpy() but it would be nice to be able to test scan with
> it. So far I understand it is already possible to make something with
> hwsim here but what about the zero symbol rate and the "waiting
> period" is zero?
Before this series: many drivers would not set the symbol duration
properly. In this case the scan will likely not work because wait
periods will be too short. But that's how it is, we miss some
information.
But for hwsim, I've handled a lot of situations so yes, there are
still channels that won't have a proper symbol duration because I just
don't know them, but for most of them (several pages) it will work like
a charm.
>
> btw:
> Also for testing with hwsim and the missing features which currently
> exist. Can we implement some user space test program which replies
> (active scan) or sends periodically something out via AF_PACKET raw
> and a monitor interface that should work to test if it is working?
We already have all this handled, no need for extra software. You can
test active and passive scans between two hwsim devices already:
# iwpan dev wpan0 beacons send interval 15
# iwpan dev wpan1 scan type active duration 1
# iwpan dev wpan0 beacons stop
or
# iwpan dev wpan0 beacons send interval 1
# iwpan dev wpan1 scan type passive duration 2
# iwpan dev wpan0 beacons stop
> Ideally we could do that very easily with scapy (not sure about their
> _upstream_ 802.15.4 support). I hope I got that right that there is
> still something missing but we could fake it in such a way (just for
> hwsim testing).
I hope the above will match your expectations.
Thanks,
Miquèl
Hi,
On Mon, 17 Jan 2022 at 04:12, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Sun, 16 Jan 2022 18:21:16 -0500:
>
> > Hi,
> >
> > On Fri, 14 Jan 2022 at 05:21, Miquel Raynal <[email protected]> wrote:
> > >
> > > Hi Alexander,
> > >
> > > [email protected] wrote on Thu, 13 Jan 2022 18:34:00 -0500:
> > >
> > > > Hi,
> > > >
> > > > On Thu, 13 Jan 2022 at 06:16, Miquel Raynal <[email protected]> wrote:
> > > > >
> > > > > Hi Alexander,
> > > > >
> > > > > [email protected] wrote on Wed, 12 Jan 2022 17:26:14 -0500:
> > > > >
> > > > > > Hi,
> > > > > >
> > > > > > On Wed, 12 Jan 2022 at 12:33, Miquel Raynal <[email protected]> wrote:
> > > > > > >
> > > > > > > The core now knows how to set the symbol duration in a few cases, when
> > > > > > > drivers correctly advertise the protocols used on each channel. For
> > > > > > > these drivers, there is no more need to bother with symbol duration, so
> > > > > > > just drop the duplicated code.
> > > > > > >
> > > > > > > Signed-off-by: Miquel Raynal <[email protected]>
> > > > > > > ---
> > > > > > > drivers/net/ieee802154/ca8210.c | 1 -
> > > > > > > drivers/net/ieee802154/mcr20a.c | 2 --
> > > > > > > 2 files changed, 3 deletions(-)
> > > > > > >
> > > > > > > diff --git a/drivers/net/ieee802154/ca8210.c b/drivers/net/ieee802154/ca8210.c
> > > > > > > index 82b2a173bdbd..d3a9e4fe05f4 100644
> > > > > > > --- a/drivers/net/ieee802154/ca8210.c
> > > > > > > +++ b/drivers/net/ieee802154/ca8210.c
> > > > > > > @@ -2977,7 +2977,6 @@ static void ca8210_hw_setup(struct ieee802154_hw *ca8210_hw)
> > > > > > > ca8210_hw->phy->cca.mode = NL802154_CCA_ENERGY_CARRIER;
> > > > > > > ca8210_hw->phy->cca.opt = NL802154_CCA_OPT_ENERGY_CARRIER_AND;
> > > > > > > ca8210_hw->phy->cca_ed_level = -9800;
> > > > > > > - ca8210_hw->phy->symbol_duration = 16 * 1000;
> > > > > > > ca8210_hw->phy->lifs_period = 40;
> > > > > > > ca8210_hw->phy->sifs_period = 12;
> > > > > > > ca8210_hw->flags =
> > > > > > > diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> > > > > > > index 8aa87e9bf92e..da2ab19cb5ee 100644
> > > > > > > --- a/drivers/net/ieee802154/mcr20a.c
> > > > > > > +++ b/drivers/net/ieee802154/mcr20a.c
> > > > > > > @@ -975,7 +975,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > > > >
> > > > > > > dev_dbg(printdev(lp), "%s\n", __func__);
> > > > > > >
> > > > > > > - phy->symbol_duration = 16 * 1000;
> > > > > > > phy->lifs_period = 40;
> > > > > > > phy->sifs_period = 12;
> > > > > > >
> > > > > > > @@ -1010,7 +1009,6 @@ static void mcr20a_hw_setup(struct mcr20a_local *lp)
> > > > > > > phy->current_page = 0;
> > > > > > > /* MCR20A default reset value */
> > > > > > > phy->current_channel = 20;
> > > > > > > - phy->symbol_duration = 16 * 1000;
> > > > > > > phy->supported.tx_powers = mcr20a_powers;
> > > > > > > phy->supported.tx_powers_size = ARRAY_SIZE(mcr20a_powers);
> > > > > > > phy->cca_ed_level = phy->supported.cca_ed_levels[75];
> > > > > >
> > > > > > What's about the atrf86230 driver?
> > > > >
> > > > > I couldn't find reliable information about what this meant:
> > > > >
> > > > > /* SUB:0 and BPSK:0 -> BPSK-20 */
> > > > > /* SUB:1 and BPSK:0 -> BPSK-40 */
> > > > > /* SUB:0 and BPSK:1 -> OQPSK-100/200/400 */
> > > > > /* SUB:1 and BPSK:1 -> OQPSK-250/500/1000 */
> > > > >
> > > > > None of these comments match the spec so I don't know what to put
> > > > > there. If you know what these protocols are, I will immediately
> > > > > provide this information into the driver and ensure the core handles
> > > > > these durations properly before dropping the symbol_durations settings
> > > > > from the code.
> > > >
> > > > I think those are from the transceiver datasheets (which are free to
> > > > access). Can you not simply merge them or is there a conflict?
> > >
> > > Actually I misread the driver, it supports several kind of chips with
> > > different channel settings and this disturbed me. I downloaded the
> > > datasheet and figured that the number after the protocol is the bit
> > > rate. This helped me to make the connection with what I already know,
> > > so both atusb and atrf86230 drivers have been converted too.
> >
> > and what is about hwsim? I think the table gets too large then...
>
> I'm sorry but I don't follow you here, what do you mean by "the table
> gets too large"?
>
The switch/case statements getting large to support the channels which
hwsim supports.
> > that's why I was thinking of moving that somehow to the regdb, however
> > this is another project as I said and this way is fine. Maybe we use a
> > kind of fallback then? The hwsim phy isn't really any 802.15.4 PHY,
> > it's just memcpy() but it would be nice to be able to test scan with
> > it. So far I understand it is already possible to make something with
> > hwsim here but what about the zero symbol rate and the "waiting
> > period" is zero?
>
> Before this series: many drivers would not set the symbol duration
> properly. In this case the scan will likely not work because wait
> periods will be too short. But that's how it is, we miss some
> information.
>
This is the case because not every transceiver was using lifs/sifs handling.
> But for hwsim, I've handled a lot of situations so yes, there are
> still channels that won't have a proper symbol duration because I just
> don't know them, but for most of them (several pages) it will work like
> a charm.
>
> >
> > btw:
> > Also for testing with hwsim and the missing features which currently
> > exist. Can we implement some user space test program which replies
> > (active scan) or sends periodically something out via AF_PACKET raw
> > and a monitor interface that should work to test if it is working?
>
> We already have all this handled, no need for extra software. You can
> test active and passive scans between two hwsim devices already:
>
> # iwpan dev wpan0 beacons send interval 15
> # iwpan dev wpan1 scan type active duration 1
> # iwpan dev wpan0 beacons stop
>
> or
>
> # iwpan dev wpan0 beacons send interval 1
> # iwpan dev wpan1 scan type passive duration 2
> # iwpan dev wpan0 beacons stop
>
> > Ideally we could do that very easily with scapy (not sure about their
> > _upstream_ 802.15.4 support). I hope I got that right that there is
> > still something missing but we could fake it in such a way (just for
> > hwsim testing).
>
> I hope the above will match your expectations.
>
I need to think and read more about... in my mind is currently the
following question: are not coordinators broadcasting that information
only? Means, isn't that a job for a coordinator?
Thanks.
- Alex
Hi Alexander,
> > > btw:
> > > Also for testing with hwsim and the missing features which currently
> > > exist. Can we implement some user space test program which replies
> > > (active scan) or sends periodically something out via AF_PACKET raw
> > > and a monitor interface that should work to test if it is working?
> >
> > We already have all this handled, no need for extra software. You can
> > test active and passive scans between two hwsim devices already:
> >
> > # iwpan dev wpan0 beacons send interval 15
> > # iwpan dev wpan1 scan type active duration 1
> > # iwpan dev wpan0 beacons stop
> >
> > or
> >
> > # iwpan dev wpan0 beacons send interval 1
> > # iwpan dev wpan1 scan type passive duration 2
> > # iwpan dev wpan0 beacons stop
> >
> > > Ideally we could do that very easily with scapy (not sure about their
> > > _upstream_ 802.15.4 support). I hope I got that right that there is
> > > still something missing but we could fake it in such a way (just for
> > > hwsim testing).
> >
> > I hope the above will match your expectations.
> >
>
> I need to think and read more about... in my mind is currently the
> following question: are not coordinators broadcasting that information
> only? Means, isn't that a job for a coordinator?
My understanding right now:
- The spec states that coordinators only can send beacons and perform
scans.
- I don't yet have the necessary infrastructure to give coordinators
more rights than regular devices or RFDs (but 40+ patches already,
don't worry this is something we have in mind)
- Right now this is the user to decide whether a device might answer
beacon requests or not. This will soon become more limited but it
greatly simplifies the logic for now.
Thanks,
Miquèl
Hi,
On Tue, 18 Jan 2022 at 05:38, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> > > > btw:
> > > > Also for testing with hwsim and the missing features which currently
> > > > exist. Can we implement some user space test program which replies
> > > > (active scan) or sends periodically something out via AF_PACKET raw
> > > > and a monitor interface that should work to test if it is working?
> > >
> > > We already have all this handled, no need for extra software. You can
> > > test active and passive scans between two hwsim devices already:
> > >
> > > # iwpan dev wpan0 beacons send interval 15
> > > # iwpan dev wpan1 scan type active duration 1
> > > # iwpan dev wpan0 beacons stop
> > >
> > > or
> > >
> > > # iwpan dev wpan0 beacons send interval 1
> > > # iwpan dev wpan1 scan type passive duration 2
> > > # iwpan dev wpan0 beacons stop
> > >
> > > > Ideally we could do that very easily with scapy (not sure about their
> > > > _upstream_ 802.15.4 support). I hope I got that right that there is
> > > > still something missing but we could fake it in such a way (just for
> > > > hwsim testing).
> > >
> > > I hope the above will match your expectations.
> > >
> >
> > I need to think and read more about... in my mind is currently the
> > following question: are not coordinators broadcasting that information
> > only? Means, isn't that a job for a coordinator?
>
> My understanding right now:
> - The spec states that coordinators only can send beacons and perform
> scans.
ok.
> - I don't yet have the necessary infrastructure to give coordinators
> more rights than regular devices or RFDs (but 40+ patches already,
> don't worry this is something we have in mind)
> - Right now this is the user to decide whether a device might answer
> beacon requests or not. This will soon become more limited but it
> greatly simplifies the logic for now.
>
There was always the idea behind it to make an "coordinator" interface
type and there is a reason for that because things e.g. filtering
becomes different than a non-coordinator interface type (known as node
interface in wpan).
At the end interface types should make a big difference in how the
"role" inside the network should be, which you can also see in
wireless as "station"/"access point" interface devices.
A non full functional device should then also not be able to act as a
coordinator e.g. it cannot create coordinator types.
However we can still make some -EOPNOTSUPP if something in a different
way should be done. This clearly breaks userspace and I am not sure if
we should worry or not worry about it in the current state of
802.15.4...
- Alex
Hi Alexander,
[email protected] wrote on Tue, 18 Jan 2022 17:43:00 -0500:
> Hi,
>
> On Tue, 18 Jan 2022 at 05:38, Miquel Raynal <[email protected]> wrote:
> >
> > Hi Alexander,
> >
> > > > > btw:
> > > > > Also for testing with hwsim and the missing features which currently
> > > > > exist. Can we implement some user space test program which replies
> > > > > (active scan) or sends periodically something out via AF_PACKET raw
> > > > > and a monitor interface that should work to test if it is working?
> > > >
> > > > We already have all this handled, no need for extra software. You can
> > > > test active and passive scans between two hwsim devices already:
> > > >
> > > > # iwpan dev wpan0 beacons send interval 15
> > > > # iwpan dev wpan1 scan type active duration 1
> > > > # iwpan dev wpan0 beacons stop
> > > >
> > > > or
> > > >
> > > > # iwpan dev wpan0 beacons send interval 1
> > > > # iwpan dev wpan1 scan type passive duration 2
> > > > # iwpan dev wpan0 beacons stop
> > > >
> > > > > Ideally we could do that very easily with scapy (not sure about their
> > > > > _upstream_ 802.15.4 support). I hope I got that right that there is
> > > > > still something missing but we could fake it in such a way (just for
> > > > > hwsim testing).
> > > >
> > > > I hope the above will match your expectations.
> > > >
> > >
> > > I need to think and read more about... in my mind is currently the
> > > following question: are not coordinators broadcasting that information
> > > only? Means, isn't that a job for a coordinator?
> >
> > My understanding right now:
> > - The spec states that coordinators only can send beacons and perform
> > scans.
>
> ok.
>
> > - I don't yet have the necessary infrastructure to give coordinators
> > more rights than regular devices or RFDs (but 40+ patches already,
> > don't worry this is something we have in mind)
> > - Right now this is the user to decide whether a device might answer
> > beacon requests or not. This will soon become more limited but it
> > greatly simplifies the logic for now.
> >
>
> There was always the idea behind it to make an "coordinator" interface
> type and there is a reason for that because things e.g. filtering
> becomes different than a non-coordinator interface type (known as node
> interface in wpan).
> At the end interface types should make a big difference in how the
> "role" inside the network should be, which you can also see in
> wireless as "station"/"access point" interface devices.
>
> A non full functional device should then also not be able to act as a
> coordinator e.g. it cannot create coordinator types.
I've added a few more parameters to be able to reflect the type of
device (ffd, rfd, rfd_r/tx) and also eventually its coordinator state.
I've hacked into nl802154 to give these information to the user and let
it device wether the device (if it's an ffd) should act as a
coordinator. This is only a first step before we create a real PAN
creation procedure of course.
I've then adapted the following patches to follow check against the
device/coordinator state to decide if an operation should be aborted or
not.
> However we can still make some -EOPNOTSUPP if something in a different
> way should be done. This clearly breaks userspace and I am not sure if
> we should worry or not worry about it in the current state of
> 802.15.4...
>
> - Alex
Thanks,
Miquèl
Hi,
On Wed, 19 Jan 2022 at 17:26, Miquel Raynal <[email protected]> wrote:
>
> Hi Alexander,
>
> [email protected] wrote on Tue, 18 Jan 2022 17:43:00 -0500:
>
> > Hi,
> >
> > On Tue, 18 Jan 2022 at 05:38, Miquel Raynal <[email protected]> wrote:
> > >
> > > Hi Alexander,
> > >
> > > > > > btw:
> > > > > > Also for testing with hwsim and the missing features which currently
> > > > > > exist. Can we implement some user space test program which replies
> > > > > > (active scan) or sends periodically something out via AF_PACKET raw
> > > > > > and a monitor interface that should work to test if it is working?
> > > > >
> > > > > We already have all this handled, no need for extra software. You can
> > > > > test active and passive scans between two hwsim devices already:
> > > > >
> > > > > # iwpan dev wpan0 beacons send interval 15
> > > > > # iwpan dev wpan1 scan type active duration 1
> > > > > # iwpan dev wpan0 beacons stop
> > > > >
> > > > > or
> > > > >
> > > > > # iwpan dev wpan0 beacons send interval 1
> > > > > # iwpan dev wpan1 scan type passive duration 2
> > > > > # iwpan dev wpan0 beacons stop
> > > > >
> > > > > > Ideally we could do that very easily with scapy (not sure about their
> > > > > > _upstream_ 802.15.4 support). I hope I got that right that there is
> > > > > > still something missing but we could fake it in such a way (just for
> > > > > > hwsim testing).
> > > > >
> > > > > I hope the above will match your expectations.
> > > > >
> > > >
> > > > I need to think and read more about... in my mind is currently the
> > > > following question: are not coordinators broadcasting that information
> > > > only? Means, isn't that a job for a coordinator?
> > >
> > > My understanding right now:
> > > - The spec states that coordinators only can send beacons and perform
> > > scans.
> >
> > ok.
> >
> > > - I don't yet have the necessary infrastructure to give coordinators
> > > more rights than regular devices or RFDs (but 40+ patches already,
> > > don't worry this is something we have in mind)
> > > - Right now this is the user to decide whether a device might answer
> > > beacon requests or not. This will soon become more limited but it
> > > greatly simplifies the logic for now.
> > >
> >
> > There was always the idea behind it to make an "coordinator" interface
> > type and there is a reason for that because things e.g. filtering
> > becomes different than a non-coordinator interface type (known as node
> > interface in wpan).
> > At the end interface types should make a big difference in how the
> > "role" inside the network should be, which you can also see in
> > wireless as "station"/"access point" interface devices.
> >
> > A non full functional device should then also not be able to act as a
> > coordinator e.g. it cannot create coordinator types.
>
> I've added a few more parameters to be able to reflect the type of
> device (ffd, rfd, rfd_r/tx) and also eventually its coordinator state.
> I've hacked into nl802154 to give these information to the user and let
> it device wether the device (if it's an ffd) should act as a
> coordinator. This is only a first step before we create a real PAN
> creation procedure of course.
>
> I've then adapted the following patches to follow check against the
> device/coordinator state to decide if an operation should be aborted or
> not.
Okay, I need to see the patches to say anything about that and how it fits.
The problem still exists that we don't currently have any distinction
to know if a device can do it or not. After this patch series every
"node interface" is allowed to scan/send beacons, where a node
interface should not be allowed to do it. If we change it later we
break things. However there is still the question if we care about it
because 802.15.4 is in such an early/experimental state. It was
"experimental" as the Kconfig EXPERIMENTAL entry still existed. It was
dropped because most people ignored this setting, that doesn't mean
that 802.15.4 ever left the experimental state.
- Alex