Skip to content

Commit

Permalink
mac802154: Handle passive scanning
Browse files Browse the repository at this point in the history
Implement the core hooks in order to provide the softMAC layer support
for passive scans. Scans are requested by the user and can be aborted.

Changing channels manually is prohibited during scans.

The implementation uses a workqueue triggered at a certain interval
depending on the symbol duration for the current channel and the
duration order provided. More advanced drivers with internal scheduling
capabilities might require additional care but there is none mainline
yet.

Received beacons during a passive scan are processed in a work queue and
their result forwarded to the upper layer.

Active scanning is not supported yet.

Co-developed-by: David Girault <david.girault@qorvo.com>
Signed-off-by: David Girault <david.girault@qorvo.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20230103165644.432209-7-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
  • Loading branch information
Miquel Raynal authored and Stefan Schmidt committed Jan 3, 2023
1 parent dd18096 commit 57588c7
Show file tree
Hide file tree
Showing 9 changed files with 427 additions and 6 deletions.
4 changes: 4 additions & 0 deletions include/linux/ieee802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions include/net/cfg802154.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,22 @@ struct cfg802154_scan_request {
struct wpan_phy *wpan_phy;
};

/**
* struct cfg802154_mac_pkt - MAC packet descriptor (beacon/command)
* @node: MAC packets to process list member
* @skb: the received sk_buff
* @sdata: the interface on which @skb was received
* @page: page configuration when @skb was received
* @channel: channel configuration when @skb was received
*/
struct cfg802154_mac_pkt {
struct list_head node;
struct sk_buff *skb;
struct ieee802154_sub_if_data *sdata;
u8 page;
u8 channel;
};

struct ieee802154_llsec_key_id {
u8 mode;
u8 id;
Expand Down
2 changes: 1 addition & 1 deletion net/mac802154/Makefile
Original file line number Diff line number Diff line change
@@ -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)
31 changes: 31 additions & 0 deletions net/mac802154/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
wpan_phy->current_channel == channel)
return 0;

/* Refuse to change channels during a scanning operation */
if (mac802154_is_scanning(local))
return -EBUSY;

ret = drv_set_channel(local, page, channel);
if (!ret) {
wpan_phy->current_page = page;
Expand Down Expand Up @@ -261,6 +265,31 @@ 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 *request)
{
struct ieee802154_sub_if_data *sdata;

sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(request->wpan_dev);

ASSERT_RTNL();

return mac802154_trigger_scan_locked(sdata, request);
}

static int mac802154_abort_scan(struct wpan_phy *wpan_phy,
struct wpan_dev *wpan_dev)
{
struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
struct ieee802154_sub_if_data *sdata;

sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev);

ASSERT_RTNL();

return mac802154_abort_scan_locked(local, sdata);
}

#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
static void
ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
Expand Down Expand Up @@ -468,6 +497,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,
Expand Down
37 changes: 34 additions & 3 deletions net/mac802154/ieee802154_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@

#include "llsec.h"

enum ieee802154_ongoing {
IEEE802154_IS_SCANNING = BIT(0),
};

/* mac802154 device private data */
struct ieee802154_local {
struct ieee802154_hw hw;
Expand All @@ -43,15 +47,26 @@ struct ieee802154_local {
struct list_head interfaces;
struct mutex iflist_mtx;

/* This one is used for scanning and other jobs not to be interfered
* with serial driver.
*/
/* Data related workqueue */
struct workqueue_struct *workqueue;
/* MAC commands related workqueue */
struct workqueue_struct *mac_wq;

struct hrtimer ifs_timer;

/* Scanning */
u8 scan_page;
u8 scan_channel;
struct cfg802154_scan_request __rcu *scan_req;
struct delayed_work scan_work;

/* Asynchronous tasks */
struct list_head rx_beacon_list;
struct work_struct rx_beacon_work;

bool started;
bool suspended;
unsigned long ongoing;

struct tasklet_struct tasklet;
struct sk_buff_head skb_queue;
Expand Down Expand Up @@ -226,6 +241,22 @@ void mac802154_unlock_table(struct net_device *dev);

int mac802154_wpan_update_llsec(struct net_device *dev);

/* PAN management handling */
void mac802154_scan_worker(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,
struct ieee802154_sub_if_data *sdata);
int mac802154_process_beacon(struct ieee802154_local *local,
struct sk_buff *skb,
u8 page, u8 channel);
void mac802154_rx_beacon_worker(struct work_struct *work);

static inline bool mac802154_is_scanning(struct ieee802154_local *local)
{
return test_bit(IEEE802154_IS_SCANNING, &local->ongoing);
}

/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
Expand Down
3 changes: 3 additions & 0 deletions net/mac802154/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ static int mac802154_slave_close(struct net_device *dev)

ASSERT_RTNL();

if (mac802154_is_scanning(local))
mac802154_abort_scan_locked(local, sdata);

netif_stop_queue(dev);
local->open_count--;

Expand Down
16 changes: 15 additions & 1 deletion net/mac802154/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,16 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
local->ops = ops;

INIT_LIST_HEAD(&local->interfaces);
INIT_LIST_HEAD(&local->rx_beacon_list);
mutex_init(&local->iflist_mtx);

tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);

skb_queue_head_init(&local->skb_queue);

INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker);
INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker);
INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);

/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
Expand Down Expand Up @@ -185,6 +188,7 @@ static void ieee802154_setup_wpan_phy_pib(struct wpan_phy *wpan_phy)
int ieee802154_register_hw(struct ieee802154_hw *hw)
{
struct ieee802154_local *local = hw_to_local(hw);
char mac_wq_name[IFNAMSIZ + 10] = {};
struct net_device *dev;
int rc = -ENOSYS;

Expand All @@ -195,6 +199,13 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)
goto out;
}

snprintf(mac_wq_name, IFNAMSIZ + 10, "%s-mac-cmds", wpan_phy_name(local->phy));
local->mac_wq = create_singlethread_workqueue(mac_wq_name);
if (!local->mac_wq) {
rc = -ENOMEM;
goto out_wq;
}

hrtimer_init(&local->ifs_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
local->ifs_timer.function = ieee802154_xmit_ifs_timer;

Expand Down Expand Up @@ -224,7 +235,7 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)

rc = wpan_phy_register(local->phy);
if (rc < 0)
goto out_wq;
goto out_mac_wq;

rtnl_lock();

Expand All @@ -243,6 +254,8 @@ int ieee802154_register_hw(struct ieee802154_hw *hw)

out_phy:
wpan_phy_unregister(local->phy);
out_mac_wq:
destroy_workqueue(local->mac_wq);
out_wq:
destroy_workqueue(local->workqueue);
out:
Expand All @@ -263,6 +276,7 @@ void ieee802154_unregister_hw(struct ieee802154_hw *hw)

rtnl_unlock();

destroy_workqueue(local->mac_wq);
destroy_workqueue(local->workqueue);
wpan_phy_unregister(local->phy);
}
Expand Down
36 changes: 35 additions & 1 deletion net/mac802154/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,31 @@ static int ieee802154_deliver_skb(struct sk_buff *skb)
return netif_receive_skb(skb);
}

void mac802154_rx_beacon_worker(struct work_struct *work)
{
struct ieee802154_local *local =
container_of(work, struct ieee802154_local, rx_beacon_work);
struct cfg802154_mac_pkt *mac_pkt;

mac_pkt = list_first_entry_or_null(&local->rx_beacon_list,
struct cfg802154_mac_pkt, node);
if (!mac_pkt)
return;

mac802154_process_beacon(local, mac_pkt->skb, mac_pkt->page, mac_pkt->channel);

list_del(&mac_pkt->node);
kfree_skb(mac_pkt->skb);
kfree(mac_pkt);
}

static int
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
struct sk_buff *skb, const struct ieee802154_hdr *hdr)
{
struct wpan_dev *wpan_dev = &sdata->wpan_dev;
struct wpan_phy *wpan_phy = sdata->local->hw.phy;
struct wpan_dev *wpan_dev = &sdata->wpan_dev;
struct cfg802154_mac_pkt *mac_pkt;
__le16 span, sshort;
int rc;

Expand Down Expand Up @@ -106,6 +125,21 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,

switch (mac_cb(skb)->type) {
case IEEE802154_FC_TYPE_BEACON:
dev_dbg(&sdata->dev->dev, "BEACON received\n");
if (!mac802154_is_scanning(sdata->local))
goto fail;

mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
if (!mac_pkt)
goto fail;

mac_pkt->skb = skb_get(skb);
mac_pkt->sdata = sdata;
mac_pkt->page = sdata->local->scan_page;
mac_pkt->channel = sdata->local->scan_channel;
list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list);
queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
return NET_RX_SUCCESS;
case IEEE802154_FC_TYPE_ACK:
case IEEE802154_FC_TYPE_MAC_CMD:
goto fail;
Expand Down
Loading

0 comments on commit 57588c7

Please sign in to comment.