Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Miquel Raynal and committed by
Stefan Schmidt
d021d218 26f88e4e

+117 -5
+2
include/net/ieee802154_netdev.h
··· 193 193 struct ieee802154_beacon_frame *beacon); 194 194 int ieee802154_mac_cmd_push(struct sk_buff *skb, void *frame, 195 195 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); 196 198 197 199 int ieee802154_max_payload(const struct ieee802154_hdr *hdr); 198 200
+13
net/ieee802154/header_ops.c
··· 307 307 } 308 308 EXPORT_SYMBOL_GPL(ieee802154_hdr_pull); 309 309 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 + 310 323 int 311 324 ieee802154_hdr_peek_addrs(const struct sk_buff *skb, struct ieee802154_hdr *hdr) 312 325 {
+20
net/mac802154/ieee802154_i.h
··· 71 71 /* Asynchronous tasks */ 72 72 struct list_head rx_beacon_list; 73 73 struct work_struct rx_beacon_work; 74 + struct list_head rx_mac_cmd_list; 75 + struct work_struct rx_mac_cmd_work; 74 76 75 77 bool started; 76 78 bool suspended; ··· 155 153 ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) 156 154 { 157 155 return test_bit(SDATA_STATE_RUNNING, &sdata->state); 156 + } 157 + 158 + static inline int ieee802154_get_mac_cmd(struct sk_buff *skb, u8 *mac_cmd) 159 + { 160 + struct ieee802154_mac_cmd_pl mac_pl; 161 + int ret; 162 + 163 + if (mac_cb(skb)->type != IEEE802154_FC_TYPE_MAC_CMD) 164 + return -EINVAL; 165 + 166 + ret = ieee802154_mac_cmd_pl_pull(skb, &mac_pl); 167 + if (ret) 168 + return ret; 169 + 170 + *mac_cmd = mac_pl.cmd_id; 171 + return 0; 158 172 } 159 173 160 174 extern struct ieee802154_mlme_ops mac802154_mlme_wpan; ··· 293 275 { 294 276 return test_bit(IEEE802154_IS_BEACONING, &local->ongoing); 295 277 } 278 + 279 + void mac802154_rx_mac_cmd_worker(struct work_struct *work); 296 280 297 281 /* interface handling */ 298 282 int ieee802154_iface_init(void);
+2
net/mac802154/main.c
··· 90 90 91 91 INIT_LIST_HEAD(&local->interfaces); 92 92 INIT_LIST_HEAD(&local->rx_beacon_list); 93 + INIT_LIST_HEAD(&local->rx_mac_cmd_list); 93 94 mutex_init(&local->iflist_mtx); 94 95 95 96 tasklet_setup(&local->tasklet, ieee802154_tasklet_handler); ··· 101 100 INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker); 102 101 INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker); 103 102 INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker); 103 + INIT_WORK(&local->rx_mac_cmd_work, mac802154_rx_mac_cmd_worker); 104 104 105 105 /* init supported flags with 802.15.4 default ranges */ 106 106 phy->supported.max_minbe = 8;
+69 -1
net/mac802154/rx.c
··· 47 47 kfree(mac_pkt); 48 48 } 49 49 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 + 50 106 static int 51 107 ieee802154_subif_frame(struct ieee802154_sub_if_data *sdata, 52 108 struct sk_buff *skb, const struct ieee802154_hdr *hdr) ··· 196 140 list_add_tail(&mac_pkt->node, &sdata->local->rx_beacon_list); 197 141 queue_work(sdata->local->mac_wq, &sdata->local->rx_beacon_work); 198 142 return NET_RX_SUCCESS; 199 - case IEEE802154_FC_TYPE_ACK: 143 + 200 144 case IEEE802154_FC_TYPE_MAC_CMD: 145 + dev_dbg(&sdata->dev->dev, "MAC COMMAND received\n"); 146 + mac_pkt = kzalloc(sizeof(*mac_pkt), GFP_ATOMIC); 147 + if (!mac_pkt) 148 + goto fail; 149 + 150 + mac_pkt->skb = skb_get(skb); 151 + mac_pkt->sdata = sdata; 152 + list_add_tail(&mac_pkt->node, &sdata->local->rx_mac_cmd_list); 153 + queue_work(sdata->local->mac_wq, &sdata->local->rx_mac_cmd_work); 154 + return NET_RX_SUCCESS; 155 + 156 + case IEEE802154_FC_TYPE_ACK: 201 157 goto fail; 202 158 203 159 case IEEE802154_FC_TYPE_DATA:
+11 -4
net/mac802154/scan.c
··· 403 403 struct cfg802154_beacon_request *beacon_req; 404 404 struct ieee802154_sub_if_data *sdata; 405 405 struct wpan_dev *wpan_dev; 406 + u8 interval; 406 407 int ret; 407 408 408 409 rcu_read_lock(); ··· 424 423 } 425 424 426 425 wpan_dev = beacon_req->wpan_dev; 426 + interval = beacon_req->interval; 427 427 428 428 rcu_read_unlock(); 429 429 ··· 434 432 dev_err(&sdata->dev->dev, 435 433 "Beacon could not be transmitted (%d)\n", ret); 436 434 437 - queue_delayed_work(local->mac_wq, &local->beacon_work, 438 - local->beacon_interval); 435 + if (interval < IEEE802154_ACTIVE_SCAN_DURATION) 436 + queue_delayed_work(local->mac_wq, &local->beacon_work, 437 + local->beacon_interval); 439 438 } 440 439 441 440 int mac802154_stop_beacons_locked(struct ieee802154_local *local, ··· 491 488 local->beacon.mhr.source.pan_id = request->wpan_dev->pan_id; 492 489 local->beacon.mhr.source.extended_addr = request->wpan_dev->extended_addr; 493 490 local->beacon.mac_pl.beacon_order = request->interval; 494 - local->beacon.mac_pl.superframe_order = request->interval; 491 + if (request->interval <= IEEE802154_MAX_SCAN_DURATION) 492 + local->beacon.mac_pl.superframe_order = request->interval; 495 493 local->beacon.mac_pl.final_cap_slot = 0xf; 496 494 local->beacon.mac_pl.battery_life_ext = 0; 497 - /* TODO: Fill this field depending on the coordinator capacity */ 495 + /* TODO: Fill this field with the coordinator situation in the network */ 498 496 local->beacon.mac_pl.pan_coordinator = 1; 499 497 local->beacon.mac_pl.assoc_permit = 1; 498 + 499 + if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION) 500 + return 0; 500 501 501 502 /* Start the beacon work */ 502 503 local->beacon_interval =