Skip to content

Commit d021d21

Browse files
miquelraynalStefan-Schmidt
authored andcommitted
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>
1 parent 26f88e4 commit d021d21

6 files changed

Lines changed: 117 additions & 5 deletions

File tree

include/net/ieee802154_netdev.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ int ieee802154_beacon_push(struct sk_buff *skb,
193193
struct ieee802154_beacon_frame *beacon);
194194
int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame,
195195
const void *pl, unsigned int pl_len);
196+
int ieee802154_mac_cmd_pl_pull(struct sk_buff *skb,
197+
struct ieee802154_mac_cmd_pl *mac_pl);
196198

197199
int ieee802154_max_payload(const struct ieee802154_hdr *hdr);
198200

net/ieee802154/header_ops.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,19 @@ ieee802154_hdr_pull(struct sk_buff *skb, struct ieee802154_hdr *hdr)
307307
}
308308
EXPORT_SYMBOL_GPL(ieee802154_hdr_pull);
309309

310+
int ieee802154_mac_cmd_pl_pull(struct sk_buff *skb,
311+
struct ieee802154_mac_cmd_pl *mac_pl)
312+
{
313+
if (!pskb_may_pull(skb, sizeof(*mac_pl)))
314+
return -EINVAL;
315+
316+
memcpy(mac_pl, skb->data, sizeof(*mac_pl));
317+
skb_pull(skb, sizeof(*mac_pl));
318+
319+
return 0;
320+
}
321+
EXPORT_SYMBOL_GPL(ieee802154_mac_cmd_pl_pull);
322+
310323
int
311324
ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr)
312325
{

net/mac802154/ieee802154_i.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ struct ieee802154_local {
7171
/* Asynchronous tasks */
7272
struct list_head rx_beacon_list;
7373
struct work_struct rx_beacon_work;
74+
struct list_head rx_mac_cmd_list;
75+
struct work_struct rx_mac_cmd_work;
7476

7577
bool started;
7678
bool suspended;
@@ -155,6 +157,22 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata)
155157
return test_bit(SDATA_STATE_RUNNING, &sdata->state);
156158
}
157159

160+
static inline int ieee802154_get_mac_cmd(struct sk_buff *skb, u8 *mac_cmd)
161+
{
162+
struct ieee802154_mac_cmd_pl mac_pl;
163+
int ret;
164+
165+
if (mac_cb(skb)->type != IEEE802154_FC_TYPE_MAC_CMD)
166+
return -EINVAL;
167+
168+
ret = ieee802154_mac_cmd_pl_pull(skb, &mac_pl);
169+
if (ret)
170+
return ret;
171+
172+
*mac_cmd = mac_pl.cmd_id;
173+
return 0;
174+
}
175+
158176
extern struct ieee802154_mlme_ops mac802154_mlme_wpan;
159177

160178
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)
276294
return test_bit(IEEE802154_IS_BEACONING, &local->ongoing);
277295
}
278296

297+
void mac802154_rx_mac_cmd_worker(struct work_struct *work);
298+
279299
/* interface handling */
280300
int ieee802154_iface_init(void);
281301
void ieee802154_iface_exit(void);

net/mac802154/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops)
9090

9191
INIT_LIST_HEAD(&local->interfaces);
9292
INIT_LIST_HEAD(&local->rx_beacon_list);
93+
INIT_LIST_HEAD(&local->rx_mac_cmd_list);
9394
mutex_init(&local->iflist_mtx);
9495

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

104106
/* init supported flags with 802.15.4 default ranges */
105107
phy->supported.max_minbe = 8;

net/mac802154/rx.c

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,62 @@ void mac802154_rx_beacon_worker(struct work_struct *work)
4747
kfree(mac_pkt);
4848
}
4949

50+
static bool mac802154_should_answer_beacon_req(struct ieee802154_local *local)
51+
{
52+
struct cfg802154_beacon_request *beacon_req;
53+
unsigned int interval;
54+
55+
rcu_read_lock();
56+
beacon_req = rcu_dereference(local->beacon_req);
57+
if (!beacon_req) {
58+
rcu_read_unlock();
59+
return false;
60+
}
61+
62+
interval = beacon_req->interval;
63+
rcu_read_unlock();
64+
65+
if (!mac802154_is_beaconing(local))
66+
return false;
67+
68+
return interval == IEEE802154_ACTIVE_SCAN_DURATION;
69+
}
70+
71+
void mac802154_rx_mac_cmd_worker(struct work_struct *work)
72+
{
73+
struct ieee802154_local *local =
74+
container_of(work, struct ieee802154_local, rx_mac_cmd_work);
75+
struct cfg802154_mac_pkt *mac_pkt;
76+
u8 mac_cmd;
77+
int rc;
78+
79+
mac_pkt = list_first_entry_or_null(&local->rx_mac_cmd_list,
80+
struct cfg802154_mac_pkt, node);
81+
if (!mac_pkt)
82+
return;
83+
84+
rc = ieee802154_get_mac_cmd(mac_pkt->skb, &mac_cmd);
85+
if (rc)
86+
goto out;
87+
88+
switch (mac_cmd) {
89+
case IEEE802154_CMD_BEACON_REQ:
90+
dev_dbg(&mac_pkt->sdata->dev->dev, "processing BEACON REQ\n");
91+
if (!mac802154_should_answer_beacon_req(local))
92+
break;
93+
94+
queue_delayed_work(local->mac_wq, &local->beacon_work, 0);
95+
break;
96+
default:
97+
break;
98+
}
99+
100+
out:
101+
list_del(&mac_pkt->node);
102+
kfree_skb(mac_pkt->skb);
103+
kfree(mac_pkt);
104+
}
105+
50106
static int
51107
ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
52108
struct sk_buff *skb, const struct ieee802154_hdr *hdr)
@@ -140,8 +196,20 @@ ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata,
140196
list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list);
141197
queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work);
142198
return NET_RX_SUCCESS;
143-
case IEEE802154_FC_TYPE_ACK:
199+
144200
case IEEE802154_FC_TYPE_MAC_CMD:
201+
dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n");
202+
mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC);
203+
if (!mac_pkt)
204+
goto fail;
205+
206+
mac_pkt->skb = skb_get(skb);
207+
mac_pkt->sdata = sdata;
208+
list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list);
209+
queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work);
210+
return NET_RX_SUCCESS;
211+
212+
case IEEE802154_FC_TYPE_ACK:
145213
goto fail;
146214

147215
case IEEE802154_FC_TYPE_DATA:

net/mac802154/scan.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ void mac802154_beacon_worker(struct work_struct *work)
403403
struct cfg802154_beacon_request *beacon_req;
404404
struct ieee802154_sub_if_data *sdata;
405405
struct wpan_dev *wpan_dev;
406+
u8 interval;
406407
int ret;
407408

408409
rcu_read_lock();
@@ -423,6 +424,7 @@ void mac802154_beacon_worker(struct work_struct *work)
423424
}
424425

425426
wpan_dev = beacon_req->wpan_dev;
427+
interval = beacon_req->interval;
426428

427429
rcu_read_unlock();
428430

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

435-
queue_delayed_work(local->mac_wq, &local->beacon_work,
436-
local->beacon_interval);
437+
if (interval < IEEE802154_ACTIVE_SCAN_DURATION)
438+
queue_delayed_work(local->mac_wq, &local->beacon_work,
439+
local->beacon_interval);
437440
}
438441

439442
int mac802154_stop_beacons_locked(struct ieee802154_local *local,
@@ -488,13 +491,17 @@ int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata,
488491
local->beacon.mhr.source.pan_id = request->wpan_dev->pan_id;
489492
local->beacon.mhr.source.extended_addr = request->wpan_dev->extended_addr;
490493
local->beacon.mac_pl.beacon_order = request->interval;
491-
local->beacon.mac_pl.superframe_order = request->interval;
494+
if (request->interval <= IEEE802154_MAX_SCAN_DURATION)
495+
local->beacon.mac_pl.superframe_order = request->interval;
492496
local->beacon.mac_pl.final_cap_slot = 0xf;
493497
local->beacon.mac_pl.battery_life_ext = 0;
494-
/* TODO: Fill this field depending on the coordinator capacity */
498+
/* TODO: Fill this field with the coordinator situation in the network */
495499
local->beacon.mac_pl.pan_coordinator = 1;
496500
local->beacon.mac_pl.assoc_permit = 1;
497501

502+
if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION)
503+
return 0;
504+
498505
/* Start the beacon work */
499506
local->beacon_interval =
500507
mac802154_scan_get_channel_time(request->interval,

0 commit comments

Comments
 (0)