summaryrefslogtreecommitdiff
path: root/net/mac802154/scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac802154/scan.c')
-rw-r--r--net/mac802154/scan.c68
1 files changed, 62 insertions, 6 deletions
diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
index 5c191bedd72c..d9658f2c4ae6 100644
--- a/net/mac802154/scan.c
+++ b/net/mac802154/scan.c
@@ -18,8 +18,12 @@
#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);
@@ -354,6 +403,7 @@ void mac802154_beacon_worker(struct work_struct *work)
struct cfg802154_beacon_request *beacon_req;
struct ieee802154_sub_if_data *sdata;
struct wpan_dev *wpan_dev;
+ u8 interval;
int ret;
rcu_read_lock();
@@ -374,6 +424,7 @@ void mac802154_beacon_worker(struct work_struct *work)
}
wpan_dev = beacon_req->wpan_dev;
+ interval = beacon_req->interval;
rcu_read_unlock();
@@ -383,8 +434,9 @@ void mac802154_beacon_worker(struct work_struct *work)
dev_err(&sdata->dev->dev,
"Beacon could not be transmitted (%d)\n", ret);
- queue_delayed_work(local->mac_wq, &local->beacon_work,
- local->beacon_interval);
+ if (interval < IEEE802154_ACTIVE_SCAN_DURATION)
+ queue_delayed_work(local->mac_wq, &local->beacon_work,
+ local->beacon_interval);
}
int mac802154_stop_beacons_locked(struct ieee802154_local *local,
@@ -439,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.extended_addr = request->wpan_dev->extended_addr;
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.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.assoc_permit = 1;
+ if (request->interval == IEEE802154_ACTIVE_SCAN_DURATION)
+ return 0;
+
/* Start the beacon work */
local->beacon_interval =
mac802154_scan_get_channel_time(request->interval,