Skip to content

Commit

Permalink
mac802154: Handle received BEACON_REQ
Browse files Browse the repository at this point in the history
When performing an active scan, devices emit BEACON_REQ which
must be answered by other PANs receiving the request, unless they are
already passively sending beacons.

Answering a beacon request becomes a duty when the user tells us to send
beacons and the request provides an interval of 15.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20230310145346.1397068-5-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
  • Loading branch information
miquelraynal authored and Stefan-Schmidt committed Mar 23, 2023
1 parent 26f88e4 commit d021d21
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 5 deletions.
2 changes: 2 additions & 0 deletions include/net/ieee802154_netdev.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ int ieee802154_beacon_push(struct sk_buff *skb,
struct ieee802154_beacon_frame *beacon);
int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame,
const void *pl, unsigned int pl_len);
int ieee802154_mac_cmd_pl_pull(struct sk_buff *skb,
struct ieee802154_mac_cmd_pl *mac_pl);

int ieee802154_max_payload(const struct ieee802154_hdr *hdr);

Expand Down
13 changes: 13 additions & 0 deletions net/ieee802154/header_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,19 @@ ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
}
EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);

int ieee802154_mac_cmd_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_mac_cmd_pl_pull);

int
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
{
Expand Down
20 changes: 20 additions & 0 deletions net/mac802154/ieee802154_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ struct ieee802154_local {
/* Asynchronous tasks */
struct list_head rx_beacon_list;
struct work_struct rx_beacon_work;
struct list_head rx_mac_cmd_list;
struct work_struct rx_mac_cmd_work;

bool started;
bool suspended;
Expand Down Expand Up @@ -155,6 +157,22 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
return test_bit(SDATA_STATE_RUNNING, &sdata->state);
}

static inline int ieee802154_get_mac_cmd(struct sk_buff *skb, u8 *mac_cmd)
{
struct ieee802154_mac_cmd_pl mac_pl;
int ret;

if (mac_cb(skb)->type != IEEE802154_FC_TYPE_MAC_CMD)
return -EINVAL;

ret = ieee802154_mac_cmd_pl_pull(skb, &mac_pl);
if (ret)
return ret;

*mac_cmd = mac_pl.cmd_id;
return 0;
}

extern struct ieee802154_mlme_ops mac802154_mlme_wpan;

void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
Expand Down Expand Up @@ -276,6 +294,8 @@ static inline bool mac802154_is_beaconing(struct ieee802154_local *local)
return test_bit(IEEE802154_IS_BEACONING, &local->ongoing);
}

void mac802154_rx_mac_cmd_worker(struct work_struct *work);

/* interface handling */
int ieee802154_iface_init(void);
void ieee802154_iface_exit(void);
Expand Down
2 changes: 2 additions & 0 deletions net/mac802154/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)

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

tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
Expand All @@ -100,6 +101,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker);
INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);
INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker);
INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker);

/* init supported flags with 802.15.4 default ranges */
phy->supported.max_minbe = 8;
Expand Down
70 changes: 69 additions & 1 deletion net/mac802154/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,62 @@ void mac802154_rx_beacon_worker(struct work_struct *work)
kfree(mac_pkt);
}

static bool mac802154_should_answer_beacon_req(struct ieee802154_local *local)
{
struct cfg802154_beacon_request *beacon_req;
unsigned int interval;

rcu_read_lock();
beacon_req = rcu_dereference(local->beacon_req);
if (!beacon_req) {
rcu_read_unlock();
return false;
}

interval = beacon_req->interval;
rcu_read_unlock();

if (!mac802154_is_beaconing(local))
return false;

return interval == IEEE802154_ACTIVE_SCAN_DURATION;
}

void mac802154_rx_mac_cmd_worker(struct work_struct *work)
{
struct ieee802154_local *local =
container_of(work, struct ieee802154_local, rx_mac_cmd_work);
struct cfg802154_mac_pkt *mac_pkt;
u8 mac_cmd;
int rc;

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

rc = ieee802154_get_mac_cmd(mac_pkt->skb, &mac_cmd);
if (rc)
goto out;

switch (mac_cmd) {
case IEEE802154_CMD_BEACON_REQ:
dev_dbg(&mac_pkt->sdata->dev->dev, "processing BEACON REQ\n");
if (!mac802154_should_answer_beacon_req(local))
break;

queue_delayed_work(local->mac_wq, &local->beacon_work, 0);
break;
default:
break;
}

out:
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)
Expand Down Expand Up @@ -140,8 +196,20 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
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:
dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n");
mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
if (!mac_pkt)
goto fail;

mac_pkt->skb = skb_get(skb);
mac_pkt->sdata = sdata;
list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);
return NET_RX_SUCCESS;

case IEEE802154_FC_TYPE_ACK:
goto fail;

case IEEE802154_FC_TYPE_DATA:
Expand Down
15 changes: 11 additions & 4 deletions net/mac802154/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ void mac802154_beacon_worker(struct work_struct *work)
struct cfg802154_beacon_request *beacon_req;
struct ieee802154_sub_if_data *sdata;
struct wpan_dev *wpan_dev;
u8 interval;
int ret;

rcu_read_lock();
Expand All @@ -423,6 +424,7 @@ void mac802154_beacon_worker(struct work_struct *work)
}

wpan_dev = beacon_req->wpan_dev;
interval = beacon_req->interval;

rcu_read_unlock();

Expand All @@ -432,8 +434,9 @@ void mac802154_beacon_worker(struct work_struct *work)
dev_err(&sdata->dev->dev,
"Beacon could not be transmitted (%d)\n", ret);

queue_delayed_work(local->mac_wq, &local->beacon_work,
local->beacon_interval);
if (interval < IEEE802154_ACTIVE_SCAN_DURATION)
queue_delayed_work(local->mac_wq, &local->beacon_work,
local->beacon_interval);
}

int mac802154_stop_beacons_locked(struct ieee802154_local *local,
Expand Down Expand Up @@ -488,13 +491,17 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
local->beacon.mhr.source.pan_id = request->wpan_dev->pan_id;
local->beacon.mhr.source.extended_addr = 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;
/* TODO: Fill this field depending on the coordinator capacity */
/* TODO: Fill this field with the coordinator situation in the network */
local->beacon.mac_pl.pan_coordinator = 1;
local->beacon.mac_pl.assoc_permit = 1;

if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION)
return 0;

/* Start the beacon work */
local->beacon_interval =
mac802154_scan_get_channel_time(request->interval,
Expand Down

0 comments on commit d021d21

Please sign in to comment.