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

mac802154: Handle basic beaconing

Implement the core hooks in order to provide the softMAC layer support
for sending beacons. Coordinators may be requested to send beacons in a
beacon enabled PAN in order for the other devices around to self
discover the available PANs automatically.

Changing the channels is prohibited while a beacon operation is
ongoing.

The implementation uses a workqueue triggered at a certain interval
depending on the symbol duration for the current channel and the
interval order provided.

Sending beacons in response to a BEACON_REQ frame (ie. answering active
scans) is not yet supported.

This initial patchset has no security support (llsec).

Co-developed-by: David Girault <david.girault@qorvo.com>
Signed-off-by: David Girault <david.girault@qorvo.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20230125102923.135465-3-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>

authored by

Miquel Raynal and committed by
Stefan Schmidt
3accf476 9bc11450

+246 -3
+16
include/net/ieee802154_netdev.h
··· 129 129 IEEE802154_MULTIPURPOSE_STD = IEEE802154_2003_STD, 130 130 }; 131 131 132 + enum ieee802154_addressing_mode { 133 + IEEE802154_NO_ADDRESSING, 134 + IEEE802154_RESERVED, 135 + IEEE802154_SHORT_ADDRESSING, 136 + IEEE802154_EXTENDED_ADDRESSING, 137 + }; 138 + 132 139 struct ieee802154_hdr { 133 140 struct ieee802154_hdr_fc fc; 134 141 u8 seq; 135 142 struct ieee802154_addr source; 136 143 struct ieee802154_addr dest; 137 144 struct ieee802154_sechdr sec; 145 + }; 146 + 147 + struct ieee802154_beacon_frame { 148 + struct ieee802154_hdr mhr; 149 + struct ieee802154_beacon_hdr mac_pl; 138 150 }; 139 151 140 152 /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from ··· 173 161 * header_ops.parse 174 162 */ 175 163 int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr); 164 + 165 + /* pushes a beacon frame into an skb */ 166 + int ieee802154_beacon_push(struct sk_buff *skb, 167 + struct ieee802154_beacon_frame *beacon); 176 168 177 169 int ieee802154_max_payload(const struct ieee802154_hdr *hdr); 178 170
+24
net/ieee802154/header_ops.c
··· 120 120 } 121 121 EXPORT_SYMBOL_GPL(ieee802154_hdr_push); 122 122 123 + int ieee802154_beacon_push(struct sk_buff *skb, 124 + struct ieee802154_beacon_frame *beacon) 125 + { 126 + struct ieee802154_beacon_hdr *mac_pl = &beacon->mac_pl; 127 + struct ieee802154_hdr *mhr = &beacon->mhr; 128 + int ret; 129 + 130 + skb_reserve(skb, sizeof(*mhr)); 131 + ret = ieee802154_hdr_push(skb, mhr); 132 + if (ret < 0) 133 + return ret; 134 + 135 + skb_reset_mac_header(skb); 136 + skb->mac_len = ret; 137 + 138 + skb_put_data(skb, mac_pl, sizeof(*mac_pl)); 139 + 140 + if (mac_pl->pend_short_addr_count || mac_pl->pend_ext_addr_count) 141 + return -EOPNOTSUPP; 142 + 143 + return 0; 144 + } 145 + EXPORT_SYMBOL_GPL(ieee802154_beacon_push); 146 + 123 147 static int 124 148 ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan, 125 149 struct ieee802154_addr *addr)
+29 -2
net/mac802154/cfg.c
··· 114 114 wpan_phy->current_channel == channel) 115 115 return 0; 116 116 117 - /* Refuse to change channels during a scanning operation */ 118 - if (mac802154_is_scanning(local)) 117 + /* Refuse to change channels during scanning or beaconing */ 118 + if (mac802154_is_scanning(local) || mac802154_is_beaconing(local)) 119 119 return -EBUSY; 120 120 121 121 ret = drv_set_channel(local, page, channel); ··· 288 288 ASSERT_RTNL(); 289 289 290 290 return mac802154_abort_scan_locked(local, sdata); 291 + } 292 + 293 + static int mac802154_send_beacons(struct wpan_phy *wpan_phy, 294 + struct cfg802154_beacon_request *request) 295 + { 296 + struct ieee802154_sub_if_data *sdata; 297 + 298 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(request->wpan_dev); 299 + 300 + ASSERT_RTNL(); 301 + 302 + return mac802154_send_beacons_locked(sdata, request); 303 + } 304 + 305 + static int mac802154_stop_beacons(struct wpan_phy *wpan_phy, 306 + struct wpan_dev *wpan_dev) 307 + { 308 + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); 309 + struct ieee802154_sub_if_data *sdata; 310 + 311 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev); 312 + 313 + ASSERT_RTNL(); 314 + 315 + return mac802154_stop_beacons_locked(local, sdata); 291 316 } 292 317 293 318 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL ··· 524 499 .set_ackreq_default = ieee802154_set_ackreq_default, 525 500 .trigger_scan = mac802154_trigger_scan, 526 501 .abort_scan = mac802154_abort_scan, 502 + .send_beacons = mac802154_send_beacons, 503 + .stop_beacons = mac802154_stop_beacons, 527 504 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 528 505 .get_llsec_table = ieee802154_get_llsec_table, 529 506 .lock_llsec_table = ieee802154_lock_llsec_table,
+18
net/mac802154/ieee802154_i.h
··· 23 23 24 24 enum ieee802154_ongoing { 25 25 IEEE802154_IS_SCANNING = BIT(0), 26 + IEEE802154_IS_BEACONING = BIT(1), 26 27 }; 27 28 28 29 /* mac802154 device private data */ ··· 60 59 u8 scan_channel; 61 60 struct cfg802154_scan_request __rcu *scan_req; 62 61 struct delayed_work scan_work; 62 + 63 + /* Beaconing */ 64 + unsigned int beacon_interval; 65 + struct ieee802154_beacon_frame beacon; 66 + struct cfg802154_beacon_request __rcu *beacon_req; 67 + struct delayed_work beacon_work; 63 68 64 69 /* Asynchronous tasks */ 65 70 struct list_head rx_beacon_list; ··· 262 255 static inline bool mac802154_is_scanning(struct ieee802154_local *local) 263 256 { 264 257 return test_bit(IEEE802154_IS_SCANNING, &local->ongoing); 258 + } 259 + 260 + void mac802154_beacon_worker(struct work_struct *work); 261 + int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata, 262 + struct cfg802154_beacon_request *request); 263 + int mac802154_stop_beacons_locked(struct ieee802154_local *local, 264 + struct ieee802154_sub_if_data *sdata); 265 + 266 + static inline bool mac802154_is_beaconing(struct ieee802154_local *local) 267 + { 268 + return test_bit(IEEE802154_IS_BEACONING, &local->ongoing); 265 269 } 266 270 267 271 /* interface handling */
+3
net/mac802154/iface.c
··· 305 305 if (mac802154_is_scanning(local)) 306 306 mac802154_abort_scan_locked(local, sdata); 307 307 308 + if (mac802154_is_beaconing(local)) 309 + mac802154_stop_beacons_locked(local, sdata); 310 + 308 311 netif_stop_queue(dev); 309 312 local->open_count--; 310 313
+4 -1
net/mac802154/llsec.c
··· 707 707 708 708 hlen = ieee802154_hdr_pull(skb, &hdr); 709 709 710 - if (hlen < 0 || hdr.fc.type != IEEE802154_FC_TYPE_DATA) 710 + /* TODO: control frames security support */ 711 + if (hlen < 0 || 712 + (hdr.fc.type != IEEE802154_FC_TYPE_DATA && 713 + hdr.fc.type != IEEE802154_FC_TYPE_BEACON)) 711 714 return -EINVAL; 712 715 713 716 if (!hdr.fc.security_enabled ||
+1
net/mac802154/main.c
··· 99 99 INIT_WORK(&local->sync_tx_work, ieee802154_xmit_sync_worker); 100 100 INIT_DELAYED_WORK(&local->scan_work, mac802154_scan_worker); 101 101 INIT_WORK(&local->rx_beacon_work, mac802154_rx_beacon_worker); 102 + INIT_DELAYED_WORK(&local->beacon_work, mac802154_beacon_worker); 102 103 103 104 /* init supported flags with 802.15.4 default ranges */ 104 105 phy->supported.max_minbe = 8;
+151
net/mac802154/scan.c
··· 16 16 #include "driver-ops.h" 17 17 #include "../ieee802154/nl802154.h" 18 18 19 + #define IEEE802154_BEACON_MHR_SZ 13 20 + #define IEEE802154_BEACON_PL_SZ 4 21 + #define IEEE802154_BEACON_SKB_SZ (IEEE802154_BEACON_MHR_SZ + \ 22 + IEEE802154_BEACON_PL_SZ) 23 + 19 24 /* mac802154_scan_cleanup_locked() must be called upon scan completion or abort. 20 25 * - Completions are asynchronous, not locked by the rtnl and decided by the 21 26 * scan worker. ··· 288 283 if (likely(scan_req)) 289 284 nl802154_scan_event(scan_req->wpan_phy, scan_req->wpan_dev, &desc); 290 285 rcu_read_unlock(); 286 + 287 + return 0; 288 + } 289 + 290 + static int mac802154_transmit_beacon(struct ieee802154_local *local, 291 + struct wpan_dev *wpan_dev) 292 + { 293 + struct cfg802154_beacon_request *beacon_req; 294 + struct ieee802154_sub_if_data *sdata; 295 + struct sk_buff *skb; 296 + int ret; 297 + 298 + /* Update the sequence number */ 299 + local->beacon.mhr.seq = atomic_inc_return(&wpan_dev->bsn) & 0xFF; 300 + 301 + skb = alloc_skb(IEEE802154_BEACON_SKB_SZ, GFP_KERNEL); 302 + if (!skb) 303 + return -ENOBUFS; 304 + 305 + rcu_read_lock(); 306 + beacon_req = rcu_dereference(local->beacon_req); 307 + if (unlikely(!beacon_req)) { 308 + rcu_read_unlock(); 309 + kfree_skb(skb); 310 + return -EINVAL; 311 + } 312 + 313 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(beacon_req->wpan_dev); 314 + skb->dev = sdata->dev; 315 + 316 + rcu_read_unlock(); 317 + 318 + ret = ieee802154_beacon_push(skb, &local->beacon); 319 + if (ret) { 320 + kfree_skb(skb); 321 + return ret; 322 + } 323 + 324 + return ieee802154_subif_start_xmit(skb, sdata->dev); 325 + } 326 + 327 + void mac802154_beacon_worker(struct work_struct *work) 328 + { 329 + struct ieee802154_local *local = 330 + container_of(work, struct ieee802154_local, beacon_work.work); 331 + struct cfg802154_beacon_request *beacon_req; 332 + struct ieee802154_sub_if_data *sdata; 333 + struct wpan_dev *wpan_dev; 334 + int ret; 335 + 336 + rcu_read_lock(); 337 + beacon_req = rcu_dereference(local->beacon_req); 338 + if (unlikely(!beacon_req)) { 339 + rcu_read_unlock(); 340 + return; 341 + } 342 + 343 + sdata = IEEE802154_WPAN_DEV_TO_SUB_IF(beacon_req->wpan_dev); 344 + 345 + /* Wait an arbitrary amount of time in case we cannot use the device */ 346 + if (local->suspended || !ieee802154_sdata_running(sdata)) { 347 + rcu_read_unlock(); 348 + queue_delayed_work(local->mac_wq, &local->beacon_work, 349 + msecs_to_jiffies(1000)); 350 + return; 351 + } 352 + 353 + wpan_dev = beacon_req->wpan_dev; 354 + 355 + rcu_read_unlock(); 356 + 357 + dev_dbg(&sdata->dev->dev, "Sending beacon\n"); 358 + ret = mac802154_transmit_beacon(local, wpan_dev); 359 + if (ret) 360 + dev_err(&sdata->dev->dev, 361 + "Beacon could not be transmitted (%d)\n", ret); 362 + 363 + if (local->beacon_interval >= 0) 364 + queue_delayed_work(local->mac_wq, &local->beacon_work, 365 + local->beacon_interval); 366 + } 367 + 368 + int mac802154_stop_beacons_locked(struct ieee802154_local *local, 369 + struct ieee802154_sub_if_data *sdata) 370 + { 371 + struct wpan_dev *wpan_dev = &sdata->wpan_dev; 372 + struct cfg802154_beacon_request *request; 373 + 374 + ASSERT_RTNL(); 375 + 376 + if (!mac802154_is_beaconing(local)) 377 + return -ESRCH; 378 + 379 + clear_bit(IEEE802154_IS_BEACONING, &local->ongoing); 380 + cancel_delayed_work(&local->beacon_work); 381 + request = rcu_replace_pointer(local->beacon_req, NULL, 1); 382 + if (!request) 383 + return 0; 384 + kfree_rcu(request); 385 + 386 + nl802154_beaconing_done(wpan_dev); 387 + 388 + return 0; 389 + } 390 + 391 + int mac802154_send_beacons_locked(struct ieee802154_sub_if_data *sdata, 392 + struct cfg802154_beacon_request *request) 393 + { 394 + struct ieee802154_local *local = sdata->local; 395 + 396 + ASSERT_RTNL(); 397 + 398 + if (mac802154_is_beaconing(local)) 399 + mac802154_stop_beacons_locked(local, sdata); 400 + 401 + /* Store beaconing parameters */ 402 + rcu_assign_pointer(local->beacon_req, request); 403 + 404 + set_bit(IEEE802154_IS_BEACONING, &local->ongoing); 405 + 406 + memset(&local->beacon, 0, sizeof(local->beacon)); 407 + local->beacon.mhr.fc.type = IEEE802154_FC_TYPE_BEACON; 408 + local->beacon.mhr.fc.security_enabled = 0; 409 + local->beacon.mhr.fc.frame_pending = 0; 410 + local->beacon.mhr.fc.ack_request = 0; 411 + local->beacon.mhr.fc.intra_pan = 0; 412 + local->beacon.mhr.fc.dest_addr_mode = IEEE802154_NO_ADDRESSING; 413 + local->beacon.mhr.fc.version = IEEE802154_2003_STD; 414 + local->beacon.mhr.fc.source_addr_mode = IEEE802154_EXTENDED_ADDRESSING; 415 + atomic_set(&request->wpan_dev->bsn, -1); 416 + local->beacon.mhr.source.mode = IEEE802154_ADDR_LONG; 417 + local->beacon.mhr.source.pan_id = cpu_to_le16(request->wpan_dev->pan_id); 418 + local->beacon.mhr.source.extended_addr = cpu_to_le64(request->wpan_dev->extended_addr); 419 + local->beacon.mac_pl.beacon_order = request->interval; 420 + local->beacon.mac_pl.superframe_order = request->interval; 421 + local->beacon.mac_pl.final_cap_slot = 0xf; 422 + local->beacon.mac_pl.battery_life_ext = 0; 423 + /* TODO: Fill this field depending on the coordinator capacity */ 424 + local->beacon.mac_pl.pan_coordinator = 1; 425 + local->beacon.mac_pl.assoc_permit = 1; 426 + 427 + /* Start the beacon work */ 428 + local->beacon_interval = 429 + mac802154_scan_get_channel_time(request->interval, 430 + request->wpan_phy->symbol_duration); 431 + queue_delayed_work(local->mac_wq, &local->beacon_work, 0); 291 432 292 433 return 0; 293 434 }