Commit d021d218 authored by Miquel Raynal's avatar Miquel Raynal Committed by Stefan Schmidt
Browse files

mac802154: Handle received BEACON_REQ



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: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Acked-by: default avatarAlexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20230310145346.1397068-5-miquel.raynal@bootlin.com


Signed-off-by: default avatarStefan Schmidt <stefan@datenfreihafen.org>
parent 26f88e4e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);

+13 −0
Original line number Diff line number Diff line
@@ -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)
{
+20 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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;
+69 −1
Original line number Diff line number Diff line
@@ -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)
@@ -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:
Loading