blob: a7506c88d52afadfd7877726b9b8fc8cc20f4772 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <wlan/mlme/client/scanner.h>
#include "mock_device.h"
#include <lib/timekeeper/clock.h>
#include <wlan/mlme/client/channel_scheduler.h>
#include <wlan/mlme/device_interface.h>
#include <wlan/mlme/mac_frame.h>
#include <wlan/mlme/mlme.h>
#include <wlan/mlme/packet.h>
#include <wlan/mlme/service.h>
#include <wlan/mlme/timer.h>
#include <wlan/protocol/mac.h>
#include <fbl/ref_ptr.h>
#include <fbl/unique_ptr.h>
#include <fuchsia/wlan/mlme/c/fidl.h>
#include <fuchsia/wlan/mlme/cpp/fidl.h>
#include <gtest/gtest.h>
#include <zircon/status.h>
#include <cstring>
namespace wlan {
namespace wlan_mlme = ::fuchsia::wlan::mlme;
namespace {
const uint8_t kBeacon[] = {
0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x64, 0x00, 0x01, 0x00, 0x00, 0x09, 0x74, 0x65, 0x73, 0x74, 0x20, 0x73, 0x73, 0x69, 0x64,
};
template <typename T>
static fbl::unique_ptr<Packet> IntoPacket(const T& msg, uint32_t ordinal = 42) {
// fidl2 doesn't have a way to get the serialized size yet. 4096 bytes should be enough for
// everyone.
const size_t kBufLen = 4096;
auto packet = GetSvcPacket(kBufLen);
memset(packet->data(), 0, kBufLen);
SerializeServiceMsg(packet.get(), ordinal, msg.get());
return fbl::move(packet);
}
struct MockOnChannelHandler : OnChannelHandler {
virtual void HandleOnChannelFrame(fbl::unique_ptr<Packet>) override {}
virtual void PreSwitchOffChannel() override {}
virtual void ReturnedOnChannel() override {}
};
class ScannerTest : public ::testing::Test {
public:
ScannerTest()
: chan_sched_(&on_channel_handler_, &mock_dev_, mock_dev_.CreateTimer(1u)),
scanner_(&mock_dev_, &chan_sched_) {
mock_dev_.SetChannel(wlan_channel_t{.primary = 11, .cbw = CBW20});
SetupMessages();
}
protected:
void SetupMessages() {
req_ = wlan_mlme::ScanRequest::New();
req_->txn_id = 123;
req_->channel_list.resize(0);
req_->channel_list->push_back(1);
req_->max_channel_time = 1u;
req_->ssid.resize(0);
}
zx_status_t Start() {
auto pkt = IntoPacket(req_, fuchsia_wlan_mlme_MLMEStartScanOrdinal);
MlmeMsg<wlan_mlme::ScanRequest> start_req;
if (MlmeMsg<wlan_mlme::ScanRequest>::FromPacket(fbl::move(pkt), &start_req) != ZX_OK) {
return ZX_ERR_IO;
}
return scanner_.Start(start_req);
}
wlan_mlme::ScanResult ExpectScanResult() {
wlan_mlme::ScanResult result;
zx_status_t st =
mock_dev_.GetQueuedServiceMsg(fuchsia_wlan_mlme_MLMEOnScanResultOrdinal, &result);
EXPECT_EQ(ZX_OK, st);
return result;
}
wlan_mlme::ScanEnd ExpectScanEnd() {
wlan_mlme::ScanEnd scan_end;
zx_status_t st =
mock_dev_.GetQueuedServiceMsg(fuchsia_wlan_mlme_MLMEOnScanEndOrdinal, &scan_end);
EXPECT_EQ(ZX_OK, st);
EXPECT_EQ(123u, scan_end.txn_id);
return scan_end;
}
wlan_mlme::ScanRequestPtr req_;
MockDevice mock_dev_;
MockOnChannelHandler on_channel_handler_;
ChannelScheduler chan_sched_;
Scanner scanner_;
};
TEST_F(ScannerTest, Start) {
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
EXPECT_FALSE(scanner_.IsRunning());
EXPECT_EQ(ZX_OK, Start());
EXPECT_TRUE(scanner_.IsRunning());
EXPECT_EQ(1u, mock_dev_.GetChannelNumber());
}
TEST_F(ScannerTest, Start_InvalidChannelTimes) {
req_->min_channel_time = 2;
req_->max_channel_time = 1;
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
EXPECT_EQ(ZX_ERR_INVALID_ARGS, Start());
EXPECT_FALSE(scanner_.IsRunning());
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
auto scan_end = ExpectScanEnd();
EXPECT_EQ(wlan_mlme::ScanResultCodes::INVALID_ARGS, scan_end.code);
}
TEST_F(ScannerTest, Start_NoChannels) {
SetupMessages();
req_->channel_list.resize(0);
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
EXPECT_EQ(ZX_ERR_INVALID_ARGS, Start());
EXPECT_FALSE(scanner_.IsRunning());
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
auto scan_end = ExpectScanEnd();
EXPECT_EQ(wlan_mlme::ScanResultCodes::INVALID_ARGS, scan_end.code);
}
TEST_F(ScannerTest, Reset) {
ASSERT_EQ(ZX_OK, Start());
ASSERT_TRUE(scanner_.IsRunning());
scanner_.Reset();
EXPECT_FALSE(scanner_.IsRunning());
// TODO(tkilbourn): check all the other invariants
}
TEST_F(ScannerTest, ScanChannel) {
ASSERT_EQ(ZX_OK, Start());
auto chan = scanner_.ScanChannel();
EXPECT_EQ(1u, chan.primary);
}
TEST_F(ScannerTest, Timeout_NextChannel) {
req_->min_channel_time = 1;
req_->max_channel_time = 10;
req_->channel_list.push_back(2);
EXPECT_EQ(11u, mock_dev_.GetChannelNumber());
ASSERT_EQ(ZX_OK, Start());
ASSERT_EQ(1u, scanner_.ScanChannel().primary);
EXPECT_EQ(1u, mock_dev_.GetChannelNumber());
mock_dev_.AdvanceTime(WLAN_TU(req_->max_channel_time));
chan_sched_.HandleTimeout();
EXPECT_EQ(2u, scanner_.ScanChannel().primary);
EXPECT_EQ(2u, mock_dev_.GetChannelNumber());
}
TEST_F(ScannerTest, ScanResponse) {
ASSERT_EQ(ZX_OK, Start());
wlan_rx_info_t info;
info.valid_fields = WLAN_RX_INFO_VALID_RSSI | WLAN_RX_INFO_VALID_SNR;
info.chan = {
.primary = 1,
};
info.rssi_dbm = -75;
info.snr_dbh = 30;
auto buffer = GetBuffer(sizeof(kBeacon));
auto packet = fbl::make_unique<Packet>(fbl::move(buffer), sizeof(kBeacon));
packet->CopyCtrlFrom(info);
memcpy(packet->mut_field<uint8_t*>(0), kBeacon, sizeof(kBeacon));
chan_sched_.HandleIncomingFrame(fbl::move(packet));
mock_dev_.SetTime(zx::time(1));
chan_sched_.HandleTimeout();
auto bss = ExpectScanResult().bss;
EXPECT_EQ(0, std::memcmp(kBeacon + 16, bss.bssid.data(), 6));
EXPECT_EQ(bss.ssid->size(), static_cast<size_t>(9));
const uint8_t ssid[] = {'t', 'e', 's', 't', ' ', 's', 's', 'i', 'd'};
EXPECT_EQ(0, std::memcmp(ssid, bss.ssid->data(), sizeof(ssid)));
EXPECT_EQ(wlan_mlme::BSSTypes::INFRASTRUCTURE, bss.bss_type);
EXPECT_EQ(100u, bss.beacon_period);
EXPECT_EQ(1024u, bss.timestamp);
// EXPECT_EQ(1u, bss->channel); // IE missing. info.chan != bss->channel.
EXPECT_EQ(-75, bss.rssi_dbm);
EXPECT_EQ(WLAN_RCPI_DBMH_INVALID, bss.rcpi_dbmh);
EXPECT_EQ(30, bss.rsni_dbh);
auto scan_end = ExpectScanEnd();
EXPECT_EQ(wlan_mlme::ScanResultCodes::SUCCESS, scan_end.code);
}
} // namespace
} // namespace wlan