mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:46:16 +00:00
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: 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>
This commit is contained in:
parent
26f88e4ebd
commit
d021d218f6
@ -193,6 +193,8 @@ int ieee802154_beacon_push(struct sk_buff *skb,
|
|||||||
struct ieee802154_beacon_frame *beacon);
|
struct ieee802154_beacon_frame *beacon);
|
||||||
int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame,
|
int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame,
|
||||||
const void *pl, unsigned int pl_len);
|
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);
|
int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
|
||||||
|
|
||||||
|
@ -307,6 +307,19 @@ ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
|
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
|
int
|
||||||
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
|
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
|
||||||
{
|
{
|
||||||
|
@ -71,6 +71,8 @@ struct ieee802154_local {
|
|||||||
/* Asynchronous tasks */
|
/* Asynchronous tasks */
|
||||||
struct list_head rx_beacon_list;
|
struct list_head rx_beacon_list;
|
||||||
struct work_struct rx_beacon_work;
|
struct work_struct rx_beacon_work;
|
||||||
|
struct list_head rx_mac_cmd_list;
|
||||||
|
struct work_struct rx_mac_cmd_work;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
bool suspended;
|
bool suspended;
|
||||||
@ -155,6 +157,22 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
|
|||||||
return test_bit(SDATA_STATE_RUNNING, &sdata->state);
|
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;
|
extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
|
||||||
|
|
||||||
void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb);
|
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);
|
return test_bit(IEEE802154_IS_BEACONING, &local->ongoing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mac802154_rx_mac_cmd_worker(struct work_struct *work);
|
||||||
|
|
||||||
/* interface handling */
|
/* interface handling */
|
||||||
int ieee802154_iface_init(void);
|
int ieee802154_iface_init(void);
|
||||||
void ieee802154_iface_exit(void);
|
void ieee802154_iface_exit(void);
|
||||||
|
@ -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->interfaces);
|
||||||
INIT_LIST_HEAD(&local->rx_beacon_list);
|
INIT_LIST_HEAD(&local->rx_beacon_list);
|
||||||
|
INIT_LIST_HEAD(&local->rx_mac_cmd_list);
|
||||||
mutex_init(&local->iflist_mtx);
|
mutex_init(&local->iflist_mtx);
|
||||||
|
|
||||||
tasklet_setup(&local->tasklet, ieee802154_tasklet_handler);
|
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_DELAYED_WORK(&local->scan_work, mac802154_scan_worker);
|
||||||
INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);
|
INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker);
|
||||||
INIT_DELAYED_WORK(&local->beacon_work, mac802154_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 */
|
/* init supported flags with 802.15.4 default ranges */
|
||||||
phy->supported.max_minbe = 8;
|
phy->supported.max_minbe = 8;
|
||||||
|
@ -47,6 +47,62 @@ void mac802154_rx_beacon_worker(struct work_struct *work)
|
|||||||
kfree(mac_pkt);
|
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
|
static int
|
||||||
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
|
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
|
||||||
struct sk_buff *skb, const struct ieee802154_hdr *hdr)
|
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);
|
list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list);
|
||||||
queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
|
queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
|
||||||
return NET_RX_SUCCESS;
|
return NET_RX_SUCCESS;
|
||||||
case IEEE802154_FC_TYPE_ACK:
|
|
||||||
case IEEE802154_FC_TYPE_MAC_CMD:
|
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;
|
goto fail;
|
||||||
|
|
||||||
case IEEE802154_FC_TYPE_DATA:
|
case IEEE802154_FC_TYPE_DATA:
|
||||||
|
@ -403,6 +403,7 @@ void mac802154_beacon_worker(struct work_struct *work)
|
|||||||
struct cfg802154_beacon_request *beacon_req;
|
struct cfg802154_beacon_request *beacon_req;
|
||||||
struct ieee802154_sub_if_data *sdata;
|
struct ieee802154_sub_if_data *sdata;
|
||||||
struct wpan_dev *wpan_dev;
|
struct wpan_dev *wpan_dev;
|
||||||
|
u8 interval;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
@ -423,6 +424,7 @@ void mac802154_beacon_worker(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wpan_dev = beacon_req->wpan_dev;
|
wpan_dev = beacon_req->wpan_dev;
|
||||||
|
interval = beacon_req->interval;
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
@ -432,8 +434,9 @@ void mac802154_beacon_worker(struct work_struct *work)
|
|||||||
dev_err(&sdata->dev->dev,
|
dev_err(&sdata->dev->dev,
|
||||||
"Beacon could not be transmitted (%d)\n", ret);
|
"Beacon could not be transmitted (%d)\n", ret);
|
||||||
|
|
||||||
queue_delayed_work(local->mac_wq, &local->beacon_work,
|
if (interval < IEEE802154_ACTIVE_SCAN_DURATION)
|
||||||
local->beacon_interval);
|
queue_delayed_work(local->mac_wq, &local->beacon_work,
|
||||||
|
local->beacon_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mac802154_stop_beacons_locked(struct ieee802154_local *local,
|
int mac802154_stop_beacons_locked(struct ieee802154_local *local,
|
||||||
@ -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.pan_id = request->wpan_dev->pan_id;
|
||||||
local->beacon.mhr.source.extended_addr = request->wpan_dev->extended_addr;
|
local->beacon.mhr.source.extended_addr = request->wpan_dev->extended_addr;
|
||||||
local->beacon.mac_pl.beacon_order = request->interval;
|
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.final_cap_slot = 0xf;
|
||||||
local->beacon.mac_pl.battery_life_ext = 0;
|
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.pan_coordinator = 1;
|
||||||
local->beacon.mac_pl.assoc_permit = 1;
|
local->beacon.mac_pl.assoc_permit = 1;
|
||||||
|
|
||||||
|
if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Start the beacon work */
|
/* Start the beacon work */
|
||||||
local->beacon_interval =
|
local->beacon_interval =
|
||||||
mac802154_scan_get_channel_time(request->interval,
|
mac802154_scan_get_channel_time(request->interval,
|
||||||
|
Loading…
Reference in New Issue
Block a user