diff --git a/garnet/lib/wlan/protocol/include/wlan/protocol/if-impl.h b/garnet/lib/wlan/protocol/include/wlan/protocol/if-impl.h index edd8014a6c55b51808277b63dbc3bcfefff9a6ae..3f1860df525add476670a970ae3430cfafcdd1b1 100644 --- a/garnet/lib/wlan/protocol/include/wlan/protocol/if-impl.h +++ b/garnet/lib/wlan/protocol/include/wlan/protocol/if-impl.h @@ -242,6 +242,38 @@ typedef struct wlanif_eapol_req { uint8_t* data; } wlanif_eapol_req_t; +// Bits used to request management frame subtypes to be captured. Also used by driver to indicate +// which management frame subtypes are supported for capture. +// +// These values are set at `1 << MgmtFrameSubtypeValue` +// See IEEE Std 802.11-2016, 9.2.4.1.3, for value of each management frame subtype +enum { + WLAN_MGMT_CAPTURE_FLAG_ASSOC_REQ = 1 << 0, + WLAN_MGMT_CAPTURE_FLAG_ASSOC_RESP = 1 << 1, + WLAN_MGMT_CAPTURE_FLAG_REASSOC_REQ = 1 << 2, + WLAN_MGMT_CAPTURE_FLAG_REASSOC_RESP = 1 << 3, + WLAN_MGMT_CAPTURE_FLAG_PROBE_REQ = 1 << 4, + WLAN_MGMT_CAPTURE_FLAG_PROBE_RESP = 1 << 5, + WLAN_MGMT_CAPTURE_FLAG_TIMING_AD = 1 << 6, + + WLAN_MGMT_CAPTURE_FLAG_BEACON = 1 << 8, + WLAN_MGMT_CAPTURE_FLAG_ATIM = 1 << 9, + WLAN_MGMT_CAPTURE_FLAG_DISASSOC = 1 << 10, + WLAN_MGMT_CAPTURE_FLAG_AUTH = 1 << 11, + WLAN_MGMT_CAPTURE_FLAG_DEAUTH = 1 << 12, + WLAN_MGMT_CAPTURE_FLAG_ACTION = 1 << 13, + WLAN_MGMT_CAPTURE_FLAG_ACTION_NO_ACK = 1 << 14, +}; + +typedef struct wlanif_start_capture_frames_req { + uint32_t mgmt_frame_flags; +} wlanif_start_capture_frames_req_t; + +typedef struct wlanif_start_capture_frames_resp { + int32_t status; + uint32_t supported_mgmt_frames; +} wlanif_start_capture_frames_resp_t; + typedef struct wlanif_scan_result { uint64_t txn_id; wlanif_bss_description_t bss; @@ -459,6 +491,11 @@ typedef struct wlanif_stats_query_response { wlanif_stats_t stats; } wlanif_stats_query_response_t; +typedef struct wlanif_captured_frame_result { + size_t data_len; + uint8_t* data; +} wlanif_captured_frame_result_t; + typedef struct wlanif_impl_ifc { // MLME operations void (*on_scan_result)(void* cookie, wlanif_scan_result_t* result); @@ -480,6 +517,7 @@ typedef struct wlanif_impl_ifc { void (*signal_report)(void* cookie, wlanif_signal_report_indication_t* ind); void (*eapol_ind)(void* cookie, wlanif_eapol_indication_t* ind); void (*stats_query_resp)(void* cookie, wlanif_stats_query_response_t* resp); + void (*relay_captured_frame)(void* cookie, wlanif_captured_frame_result_t* result); // Data operations void (*data_recv)(void* cookie, void* data, size_t length, uint32_t flags); @@ -512,6 +550,9 @@ typedef struct wlanif_impl_protocol_ops { // MLME extensions void (*stats_query_req)(void* ctx); + void (*start_capture_frames)(void* ctx, wlanif_start_capture_frames_req_t* req, + wlanif_start_capture_frames_resp_t* resp); + void (*stop_capture_frames)(void* ctx); // Data operations zx_status_t (*data_queue_tx)(void* ctx, uint32_t options, ethmac_netbuf_t* netbuf); diff --git a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl index 3a081e98cc7ca736a72887cb238af9a9e121c537..5a14e859ab61750cd57c47e8662689b4443a8eeb 100644 --- a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl +++ b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme.fidl @@ -674,9 +674,9 @@ struct ResetRequest { // MLME-START.request (IEEE Std 802.11-2016, 6.3.11.2) // See dot11CountryString of IEEE Std 802.11-2016, Annex C -const uint8 countryEnvironAll = 32; // an ASCII ' ' character -const uint8 countryEnvironOutdoor = 79; // an ASCII 'O' character -const uint8 countryEnvironIndoor = 73; // an ASCII 'I' character +const uint8 countryEnvironAll = 32; // an ASCII ' ' character +const uint8 countryEnvironOutdoor = 79; // an ASCII 'O' character +const uint8 countryEnvironIndoor = 73; // an ASCII 'I' character const uint8 countryEnvironNonCountry = 88; // an ASCII 'X' character // Information derived from Country Element, IEEE Std 802.11-2016, 9.4.2.9. @@ -955,4 +955,8 @@ protocol MLME { ListMinstrelPeers() -> (MinstrelListResponse resp); GetMinstrelStats(MinstrelStatsRequest req) -> (MinstrelStatsResponse resp); + + StartCaptureFrames(StartCaptureFramesRequest req) -> (StartCaptureFramesResponse resp); + StopCaptureFrames(); + -> RelayCapturedFrame(CapturedFrameResult result); }; diff --git a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme_ext.fidl b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme_ext.fidl index 43ff5eb8ad74fdaeb3612e6f42e8899d2156cfa4..97920f967aac6eadecba6225620633b0c4e8b9d6 100644 --- a/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme_ext.fidl +++ b/sdk/fidl/fuchsia.wlan.mlme/wlan_mlme_ext.fidl @@ -82,5 +82,42 @@ enum ControlledPortState { OPEN = 1; }; +// START_CAPTURE_FRAMES.request + +/// Bits used to request management frame subtypes to be captured. Also used in +/// StartCaptureFramesResponse to indicate what management frames are supported. +/// +/// These values are set at `1 << MgmtFrameSubtypeValue` +/// See IEEE Std 802.11-2016, 9.2.4.1.3, for value of each management frame subtype +bits MgmtFrameCaptureFlags:uint32 { + ASSOC_REQ = 0x1; + ASSOC_RESP = 0x2; + REASSOC_REQ = 0x4; + REASSOC_RESP = 0x8; + PROBE_REQ = 0x10; + PROBE_RESP = 0x20; + TIMING_AD = 0x40; + BEACON = 0x100; + ATIM = 0x200; + DISASSOC = 0x400; + AUTH = 0x800; + DEAUTH = 0x1000; + ACTION = 0x2000; + ACTION_NO_ACK = 0x4000; +}; + +struct StartCaptureFramesRequest { + MgmtFrameCaptureFlags mgmt_frame_flags; +}; + +struct StartCaptureFramesResponse { + int32 status; + MgmtFrameCaptureFlags supported_mgmt_frames; +}; + +struct CapturedFrameResult { + bytes frame; +}; + // Method ordinals are defined in wlan_mlme.fidl to prevent error prone overlaps with official // MLME primitives. diff --git a/src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/cfg80211.c b/src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/cfg80211.c index ce85cc88158918a59461ff4a9a33d25ad6aad54a..6a7499d4c1cf880857b1407439669c91c7659aa9 100644 --- a/src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/cfg80211.c +++ b/src/connectivity/wlan/drivers/third_party/broadcom/brcmfmac/cfg80211.c @@ -3411,6 +3411,17 @@ zx_status_t brcmf_hook_data_queue_tx(void* ctx, uint32_t options, ethmac_netbuf_ return ZX_OK; } +void brcmf_hook_start_capture_frames(void* ctx, wlanif_start_capture_frames_req_t* req, + wlanif_start_capture_frames_resp_t* resp) { + brcmf_err("start_capture_frames not supported\n"); + resp->status = ZX_ERR_NOT_SUPPORTED; + resp->supported_mgmt_frames = 0; +} + +void brcmf_hook_stop_capture_frames(void* ctx) { + brcmf_err("stop_capture_frames not supported\n"); +} + static wlanif_impl_protocol_ops_t if_impl_proto_ops = { .start = brcmf_if_start, .stop = brcmf_if_stop, @@ -3431,6 +3442,8 @@ static wlanif_impl_protocol_ops_t if_impl_proto_ops = { .query = brcmf_hook_query, .stats_query_req = brcmf_hook_stats_query_req, .data_queue_tx = brcmf_hook_data_queue_tx, + .start_capture_frames = brcmf_hook_start_capture_frames, + .stop_capture_frames = brcmf_hook_stop_capture_frames, }; static void brcmf_release_zx_if_device(void* ctx) { diff --git a/src/connectivity/wlan/drivers/wlanif/convert.cpp b/src/connectivity/wlan/drivers/wlanif/convert.cpp index c8693b025d01c2bd8262edc439dc44902d44c7b9..0b06163a8429c53d3aad2689f8d2b017fcff675f 100644 --- a/src/connectivity/wlan/drivers/wlanif/convert.cpp +++ b/src/connectivity/wlan/drivers/wlanif/convert.cpp @@ -930,4 +930,99 @@ void ConvertIfaceStats(wlan_stats::IfaceStats* fidl_stats, const wlanif_stats_t& } } +uint32_t ConvertMgmtCaptureFlags(wlan_mlme::MgmtFrameCaptureFlags fidl_flags) { + uint32_t ret_flags = 0; + uint32_t flags = static_cast<uint32_t>(fidl_flags); + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ASSOC_REQ)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_ASSOC_REQ; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ASSOC_RESP)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_ASSOC_RESP; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::REASSOC_REQ)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_REASSOC_REQ; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::REASSOC_RESP)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_REASSOC_RESP; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::PROBE_REQ)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_PROBE_REQ; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::PROBE_RESP)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_PROBE_RESP; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::TIMING_AD)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_TIMING_AD; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::BEACON)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_BEACON; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ATIM)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_ATIM; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::DISASSOC)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_DISASSOC; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::AUTH)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_AUTH; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::DEAUTH)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_DEAUTH; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ACTION)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_ACTION; + } + if ((flags & static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ACTION_NO_ACK)) != 0) { + ret_flags |= WLAN_MGMT_CAPTURE_FLAG_ACTION_NO_ACK; + } + return ret_flags; +} + +wlan_mlme::MgmtFrameCaptureFlags ConvertMgmtCaptureFlags(uint32_t ddk_flags) { + uint32_t ret_flags = 0; + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_ASSOC_REQ) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ASSOC_REQ); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_ASSOC_RESP) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ASSOC_RESP); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_REASSOC_REQ) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::REASSOC_REQ); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_REASSOC_RESP) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::REASSOC_RESP); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_PROBE_REQ) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::PROBE_REQ); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_PROBE_RESP) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::PROBE_RESP); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_TIMING_AD) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::TIMING_AD); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_BEACON) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::BEACON); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_ATIM) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ATIM); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_DISASSOC) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::DISASSOC); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_AUTH) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::AUTH); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_DEAUTH) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::DEAUTH); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_ACTION) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ACTION); + } + if ((ddk_flags & WLAN_MGMT_CAPTURE_FLAG_ACTION_NO_ACK) != 0) { + ret_flags |= static_cast<uint32_t>(wlan_mlme::MgmtFrameCaptureFlags::ACTION_NO_ACK); + } + return static_cast<wlan_mlme::MgmtFrameCaptureFlags>(ret_flags); +} + } // namespace wlanif diff --git a/src/connectivity/wlan/drivers/wlanif/convert.h b/src/connectivity/wlan/drivers/wlanif/convert.h index 0d7bb07f1440031caea91ab8c7f9b747b316af98..3a2d18cbe6cc522bb21090f75e080f1b986b000a 100644 --- a/src/connectivity/wlan/drivers/wlanif/convert.h +++ b/src/connectivity/wlan/drivers/wlanif/convert.h @@ -46,5 +46,7 @@ uint8_t ConvertAssocResultCode(::fuchsia::wlan::mlme::AssociateResultCodes code) void ConvertBandCapabilities(::fuchsia::wlan::mlme::BandCapabilities* fidl_band, const wlanif_band_capabilities_t& band); void ConvertIfaceStats(::fuchsia::wlan::stats::IfaceStats* fidl_stats, const wlanif_stats_t& stats); +uint32_t ConvertMgmtCaptureFlags(::fuchsia::wlan::mlme::MgmtFrameCaptureFlags fidl_flags); +::fuchsia::wlan::mlme::MgmtFrameCaptureFlags ConvertMgmtCaptureFlags(uint32_t ddk_flags); } // namespace wlanif diff --git a/src/connectivity/wlan/drivers/wlanif/device.cpp b/src/connectivity/wlan/drivers/wlanif/device.cpp index 8eee372e59e7cd8f8d599e6ad06cdcc0ad9ff444..c03cccad9fa932b7be208fddf6c448aa0a194f20 100644 --- a/src/connectivity/wlan/drivers/wlanif/device.cpp +++ b/src/connectivity/wlan/drivers/wlanif/device.cpp @@ -87,6 +87,8 @@ static wlanif_impl_ifc_t wlanif_impl_ifc_ops = { { DEV(cookie)->EapolInd(ind); }, .stats_query_resp = [](void* cookie, wlanif_stats_query_response_t* resp) { DEV(cookie)->StatsQueryResp(resp); }, + .relay_captured_frame = [](void* cookie, wlanif_captured_frame_result_t* result) + { DEV(cookie)->RelayCapturedFrame(result); }, // Ethernet operations .data_recv = [](void* cookie, void* data, size_t length, uint32_t flags) @@ -652,6 +654,26 @@ void Device::SetControlledPort(wlan_mlme::SetControlledPortRequest req) { } } +void Device::StartCaptureFrames(::fuchsia::wlan::mlme::StartCaptureFramesRequest req, + StartCaptureFramesCallback cb) { + wlanif_start_capture_frames_req_t impl_req = {}; + impl_req.mgmt_frame_flags = ConvertMgmtCaptureFlags(req.mgmt_frame_flags); + + wlanif_start_capture_frames_resp_t impl_resp = {}; + + // forward request to driver + wlanif_impl_.ops->start_capture_frames(wlanif_impl_.ctx, &impl_req, &impl_resp); + + wlan_mlme::StartCaptureFramesResponse resp; + resp.status = impl_resp.status; + resp.supported_mgmt_frames = ConvertMgmtCaptureFlags(impl_resp.supported_mgmt_frames); + cb(resp); +} + +void Device::StopCaptureFrames() { + wlanif_impl_.ops->stop_capture_frames(wlanif_impl_.ctx); +} + void Device::OnScanResult(wlanif_scan_result_t* result) { std::lock_guard<std::mutex> lock(lock_); if (!binding_.is_bound()) { @@ -958,6 +980,19 @@ void Device::StatsQueryResp(wlanif_stats_query_response_t* resp) { binding_.events().StatsQueryResp(std::move(fidl_resp)); } +void Device::RelayCapturedFrame(wlanif_captured_frame_result* result) { + std::lock_guard<std::mutex> lock(lock_); + if (!binding_.is_bound()) { + return; + } + + wlan_mlme::CapturedFrameResult fidl_result; + fidl_result.frame.resize(result->data_len); + fidl_result.frame.assign(result->data, result->data + result->data_len); + + binding_.events().RelayCapturedFrame(std::move(fidl_result)); +} + zx_status_t Device::EthStart(const ethmac_ifc_protocol_t* ifc) { std::lock_guard<std::mutex> lock(lock_); ethmac_ifc_ = *ifc; diff --git a/src/connectivity/wlan/drivers/wlanif/device.h b/src/connectivity/wlan/drivers/wlanif/device.h index ccfe259667a92b24f14851cfcca15ab138c70cfd..8007dc595fe76f777436d12be926085532d371fc 100644 --- a/src/connectivity/wlan/drivers/wlanif/device.h +++ b/src/connectivity/wlan/drivers/wlanif/device.h @@ -59,6 +59,9 @@ class Device : public ::fuchsia::wlan::mlme::MLME { void MeshPeeringEstablished(::fuchsia::wlan::mlme::MeshPeeringParams params) override; void GetMeshPathTableReq(::fuchsia::wlan::mlme::GetMeshPathTableRequest req, GetMeshPathTableReqCallback cb) override; + void StartCaptureFrames(::fuchsia::wlan::mlme::StartCaptureFramesRequest req, + StartCaptureFramesCallback cb) override; + void StopCaptureFrames() override; // wlanif_impl_ifc (wlanif-impl -> ::fuchsia::wlan::mlme) void OnScanResult(wlanif_scan_result_t* result); @@ -78,6 +81,7 @@ class Device : public ::fuchsia::wlan::mlme::MLME { void SignalReport(wlanif_signal_report_indication_t* ind); void EapolInd(wlanif_eapol_indication_t* ind); void StatsQueryResp(wlanif_stats_query_response_t* resp); + void RelayCapturedFrame(wlanif_captured_frame_result* result); // wlanif_protocol_t (ethmac_protocol -> wlanif_impl_protocol) zx_status_t EthStart(const ethmac_ifc_protocol_t* ifc);