mac802154: Handle active scanning
authorMiquel Raynal <miquel.raynal@bootlin.com>
Fri, 10 Mar 2023 14:53:44 +0000 (15:53 +0100)
committerStefan Schmidt <stefan@datenfreihafen.org>
Thu, 23 Mar 2023 20:51:13 +0000 (21:51 +0100)
Active scan support is based on the current passive scan support,
cheered up with beacon requests sent after every channel change.

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/20230310145346.1397068-3-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
include/net/ieee802154_netdev.h
net/ieee802154/header_ops.c
net/mac802154/ieee802154_i.h
net/mac802154/scan.c

index da8a3e6..257c9b2 100644 (file)
@@ -74,6 +74,10 @@ struct ieee802154_beacon_hdr {
 #endif
 } __packed;
 
+struct ieee802154_mac_cmd_pl {
+       u8  cmd_id;
+} __packed;
+
 struct ieee802154_sechdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
        u8 level:3,
@@ -149,6 +153,16 @@ struct ieee802154_beacon_frame {
        struct ieee802154_beacon_hdr mac_pl;
 };
 
+struct ieee802154_mac_cmd_frame {
+       struct ieee802154_hdr mhr;
+       struct ieee802154_mac_cmd_pl mac_pl;
+};
+
+struct ieee802154_beacon_req_frame {
+       struct ieee802154_hdr mhr;
+       struct ieee802154_mac_cmd_pl mac_pl;
+};
+
 /* pushes hdr onto the skb. fields of hdr->fc that can be calculated from
  * the contents of hdr will be, and the actual value of those bits in
  * hdr->fc will be ignored. this includes the INTRA_PAN bit and the frame
@@ -174,9 +188,11 @@ int ieee802154_hdr_peek_addrs(const struct sk_buff *skb,
  */
 int ieee802154_hdr_peek(const struct sk_buff *skb, struct ieee802154_hdr *hdr);
 
-/* pushes a beacon frame into an skb */
+/* pushes/pulls various frame types into/from an skb */
 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_max_payload(const struct ieee802154_hdr *hdr);
 
index 35d384d..a5ff101 100644 (file)
@@ -120,6 +120,29 @@ ieee802154_hdr_push(struct sk_buff *skb, struct ieee802154_hdr *hdr)
 }
 EXPORT_SYMBOL_GPL(ieee802154_hdr_push);
 
+int ieee802154_mac_cmd_push(struct sk_buff *skb, void *f,
+                           const void *pl, unsigned int pl_len)
+{
+       struct ieee802154_mac_cmd_frame *frame = f;
+       struct ieee802154_mac_cmd_pl *mac_pl = &frame->mac_pl;
+       struct ieee802154_hdr *mhr = &frame->mhr;
+       int ret;
+
+       skb_reserve(skb, sizeof(*mhr));
+       ret = ieee802154_hdr_push(skb, mhr);
+       if (ret < 0)
+               return ret;
+
+       skb_reset_mac_header(skb);
+       skb->mac_len = ret;
+
+       skb_put_data(skb, mac_pl, sizeof(*mac_pl));
+       skb_put_data(skb, pl, pl_len);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ieee802154_mac_cmd_push);
+
 int ieee802154_beacon_push(struct sk_buff *skb,
                           struct ieee802154_beacon_frame *beacon)
 {
index 63bab99..7bfd541 100644 (file)
@@ -58,6 +58,7 @@ struct ieee802154_local {
        /* Scanning */
        u8 scan_page;
        u8 scan_channel;
+       struct ieee802154_beacon_req_frame scan_beacon_req;
        struct cfg802154_scan_request __rcu *scan_req;
        struct delayed_work scan_work;
 
index 9b0933a..201bfc5 100644 (file)
 
 #define IEEE802154_BEACON_MHR_SZ 13
 #define IEEE802154_BEACON_PL_SZ 4
+#define IEEE802154_MAC_CMD_MHR_SZ 23
+#define IEEE802154_MAC_CMD_PL_SZ 1
 #define IEEE802154_BEACON_SKB_SZ (IEEE802154_BEACON_MHR_SZ + \
                                  IEEE802154_BEACON_PL_SZ)
+#define IEEE802154_MAC_CMD_SKB_SZ (IEEE802154_MAC_CMD_MHR_SZ + \
+                                  IEEE802154_MAC_CMD_PL_SZ)
 
 /* mac802154_scan_cleanup_locked() must be called upon scan completion or abort.
  * - Completions are asynchronous, not locked by the rtnl and decided by the
@@ -131,6 +135,42 @@ static int mac802154_scan_find_next_chan(struct ieee802154_local *local,
        return 0;
 }
 
+static int mac802154_scan_prepare_beacon_req(struct ieee802154_local *local)
+{
+       memset(&local->scan_beacon_req, 0, sizeof(local->scan_beacon_req));
+       local->scan_beacon_req.mhr.fc.type = IEEE802154_FC_TYPE_MAC_CMD;
+       local->scan_beacon_req.mhr.fc.dest_addr_mode = IEEE802154_SHORT_ADDRESSING;
+       local->scan_beacon_req.mhr.fc.version = IEEE802154_2003_STD;
+       local->scan_beacon_req.mhr.fc.source_addr_mode = IEEE802154_NO_ADDRESSING;
+       local->scan_beacon_req.mhr.dest.mode = IEEE802154_ADDR_SHORT;
+       local->scan_beacon_req.mhr.dest.pan_id = cpu_to_le16(IEEE802154_PANID_BROADCAST);
+       local->scan_beacon_req.mhr.dest.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+       local->scan_beacon_req.mac_pl.cmd_id = IEEE802154_CMD_BEACON_REQ;
+
+       return 0;
+}
+
+static int mac802154_transmit_beacon_req(struct ieee802154_local *local,
+                                        struct ieee802154_sub_if_data *sdata)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       skb = alloc_skb(IEEE802154_MAC_CMD_SKB_SZ, GFP_KERNEL);
+       if (!skb)
+               return -ENOBUFS;
+
+       skb->dev = sdata->dev;
+
+       ret = ieee802154_mac_cmd_push(skb, &local->scan_beacon_req, NULL, 0);
+       if (ret) {
+               kfree_skb(skb);
+               return ret;
+       }
+
+       return ieee802154_mlme_tx(local, sdata, skb);
+}
+
 void mac802154_scan_worker(struct work_struct *work)
 {
        struct ieee802154_local *local =
@@ -206,6 +246,13 @@ void mac802154_scan_worker(struct work_struct *work)
                goto end_scan;
        }
 
+       if (scan_req->type == NL802154_SCAN_ACTIVE) {
+               ret = mac802154_transmit_beacon_req(local, sdata);
+               if (ret)
+                       dev_err(&sdata->dev->dev,
+                               "Error when transmitting beacon request (%d)\n", ret);
+       }
+
        ieee802154_configure_durations(wpan_phy, page, channel);
        scan_duration = mac802154_scan_get_channel_time(scan_req_duration,
                                                        wpan_phy->symbol_duration);
@@ -231,8 +278,8 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
        if (mac802154_is_scanning(local))
                return -EBUSY;
 
-       /* TODO: support other scanning type */
-       if (request->type != NL802154_SCAN_PASSIVE)
+       if (request->type != NL802154_SCAN_PASSIVE &&
+           request->type != NL802154_SCAN_ACTIVE)
                return -EOPNOTSUPP;
 
        /* Store scanning parameters */
@@ -247,6 +294,8 @@ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
        local->scan_page = request->page;
        local->scan_channel = -1;
        set_bit(IEEE802154_IS_SCANNING, &local->ongoing);
+       if (request->type == NL802154_SCAN_ACTIVE)
+               mac802154_scan_prepare_beacon_req(local);
 
        nl802154_scan_started(request->wpan_phy, request->wpan_dev);