From 954a7580bf2241e984aedc71322159327e4b7820 Mon Sep 17 00:00:00 2001 From: Itay Elenzweig Date: Sun, 5 Jan 2020 14:11:29 +0200 Subject: [PATCH] bwl: Add NL DWPAL monitor implementation Implement channel scan events processing. Implement scan triggering and dump results requests. Signed-off-by: alex kanter Signed-off-by: itay elenzweig --- .../beerocks/bwl/dwpal/mon_wlan_hal_dwpal.cpp | 243 +++++++++++++++++- .../beerocks/bwl/dwpal/mon_wlan_hal_dwpal.h | 63 ++++- .../beerocks/bwl/include/bwl/mon_wlan_hal.h | 9 +- 3 files changed, 310 insertions(+), 5 deletions(-) diff --git a/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.cpp b/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.cpp index 869296ce16..f5239709ab 100644 --- a/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.cpp +++ b/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.cpp @@ -10,13 +10,17 @@ #include #include +#include #include +#include #include +#include extern "C" { #include +#include } ////////////////////////////////////////////////////////////////////////////// @@ -62,6 +66,23 @@ static mon_wlan_hal::Event dwpal_to_bwl_event(const std::string &opcode) return mon_wlan_hal::Event::Invalid; } +static mon_wlan_hal::Event dwpal_nl_to_bwl_event(uint8_t cmd) +{ + switch (cmd) { + case NL80211_CMD_TRIGGER_SCAN: + return mon_wlan_hal::Event::Channel_Scan_Triggered; + case NL80211_CMD_NEW_SCAN_RESULTS: + return mon_wlan_hal::Event::Channel_Scan_Dump_Result; + case NL80211_CMD_SCAN_ABORTED: + return mon_wlan_hal::Event::Channel_Scan_Abort; + case SCAN_FINISH_CB: + return mon_wlan_hal::Event::Channel_Scan_Finished; + default: + LOG(ERROR) << "Unknown event received: " << int(cmd); + return mon_wlan_hal::Event::Invalid; + } +} + static void calc_curr_traffic(const uint64_t val, uint64_t &total, uint32_t &curr) { if (val >= total) { @@ -72,6 +93,37 @@ static void calc_curr_traffic(const uint64_t val, uint64_t &total, uint32_t &cur total = val; } +/** + * @brief get channel pool frquencies for channel scan parameters. + * + * @param [in] channel_pool list of channels to be scanned. + * @param [in] curr_channel channel teh radio is currently on. + * @param [in] iface radio interface name. + * @param [out] scan_params for saving channel frequencies for next scan. + * @return true on success + */ +static bool dwpal_get_channel_scan_freq(const std::vector &channel_pool, + unsigned int curr_channel, const std::string &iface, + ScanParams &scan_params) +{ + int freq_index = 0; + //configure center frequency for each scanned channel + for (auto channel : channel_pool) { + //channel validation + LOG(DEBUG) << "validating pool channel=" << channel; + if (son::wireless_utils::which_freq(curr_channel) != + son::wireless_utils::which_freq(channel)) { + LOG(ERROR) << "cannot scan channel = " << channel + << " not on the same radio interface = " << iface; + return false; + } + + scan_params.freq[freq_index] = beerocks::utils::wifi_channel_to_freq(int(channel)); + LOG(DEBUG) << "channel scan pool add center frequency=" << scan_params.freq[freq_index]; + freq_index++; + } + return true; +}; ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Implementation /////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -409,6 +461,100 @@ bool mon_wlan_hal_dwpal::sta_link_measurements_11k_request(const std::string &st return true; } +bool mon_wlan_hal_dwpal::channel_scan_trigger(int dwell_time_msec, + const std::vector &channel_pool) +{ + LOG(DEBUG) << __func__ << " received on interface=" << m_radio_info.iface_name; + + //build scan parameters + ScanParams channel_scan_params = {0}; + sScanCfgParams org_fg, new_fg; //foreground scan param + sScanCfgParamsBG org_bg, new_bg; //background scan param + + // get original scan params + if (!dwpal_get_scan_params_fg(org_fg) || !dwpal_get_scan_params_bg(org_bg)) { + LOG(ERROR) << "Failed getting original scan parameters"; + return false; + } + + // prepare new scan params with changed dwell time + new_fg = org_fg; + new_bg = org_bg; + new_fg.passive_dwell_time = dwell_time_msec; + new_fg.active_dwell_time = dwell_time_msec; + new_bg.passive_dwell_time = dwell_time_msec; + new_bg.active_dwell_time = dwell_time_msec; + + // set new scan params & get newly set values for validation + if (!dwpal_set_scan_params_fg(new_fg) || !dwpal_set_scan_params_bg(new_bg)) { + LOG(ERROR) << "Failed setting new values, restoring original scan parameters"; + dwpal_set_scan_params_fg(org_fg); + dwpal_set_scan_params_bg(org_bg); + return false; + } + + if (!dwpal_get_scan_params_fg(new_fg) || !dwpal_get_scan_params_bg(new_bg) || + (new_fg.active_dwell_time != dwell_time_msec) || + (new_fg.passive_dwell_time != dwell_time_msec) || + (new_bg.active_dwell_time != dwell_time_msec) || + (new_bg.passive_dwell_time != dwell_time_msec)) { + LOG(ERROR) << "Validation failed, restoring original scan parameters"; + dwpal_set_scan_params_fg(org_fg); + dwpal_set_scan_params_bg(org_bg); + return false; + } + + // get frequencies from channel pool and set in scan_params + if (!dwpal_get_channel_scan_freq(channel_pool, m_radio_info.channel, m_radio_info.iface_name, + channel_scan_params)) { + LOG(ERROR) << "Failed getting frequencies, restoring original scan parameters"; + dwpal_set_scan_params_fg(org_fg); + dwpal_set_scan_params_bg(org_bg); + return false; + } + + // must as single wifi won't allow scan on ap without this flag + channel_scan_params.ap_force = 1; + + if (dwpal_driver_nl_scan_trigger(get_dwpal_nl_ctx(), (char *)m_radio_info.iface_name.c_str(), + &channel_scan_params) != DWPAL_SUCCESS) { + LOG(ERROR) << " scan trigger failed! Abort scan, restoring original scan parameters"; + dwpal_set_scan_params_fg(org_fg); + dwpal_set_scan_params_bg(org_bg); + return false; + } + + // restoring channel scan params with original dwell time. + // dwpal_driver_nl_scan_trigger() API doesn't include dwell time parameter + // so we have to change and restore driver scan parameters on the fly. + // no reason to check since we restore the original params here anyway + // and the next validation will validate the change. + dwpal_set_scan_params_fg(org_fg); + dwpal_set_scan_params_bg(org_bg); + + // validate if "set" function to original values worked + if (!dwpal_get_scan_params_fg(new_fg) || !dwpal_get_scan_params_bg(new_bg) || + (new_fg.active_dwell_time != org_fg.active_dwell_time) || + (new_fg.passive_dwell_time != org_fg.passive_dwell_time) || + (new_bg.active_dwell_time != org_bg.active_dwell_time) || + (new_bg.passive_dwell_time != org_bg.passive_dwell_time)) { + LOG(ERROR) << "Validation failed, original scan parameters were not restored"; + return false; + } + + return true; +} + +bool mon_wlan_hal_dwpal::channel_scan_dump_results() +{ + if (!dwpal_nl_cmd_scan_dump()) { + LOG(ERROR) << "Channel scan results dump failed"; + return false; + } + + return true; +} + bool mon_wlan_hal_dwpal::process_dwpal_event(char *buffer, int bufLen, const std::string &opcode) { LOG(TRACE) << __func__ << " - opcode: |" << opcode << "|"; @@ -584,8 +730,101 @@ bool mon_wlan_hal_dwpal::process_dwpal_event(char *buffer, int bufLen, const std bool mon_wlan_hal_dwpal::process_dwpal_nl_event(struct nl_msg *msg) { - LOG(ERROR) << __func__ << "isn't implemented by this derived and shouldn't be called"; - return false; + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlh); + char ifname[IF_NAMESIZE] = "\0"; + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); + + if ((tb[NL80211_ATTR_IFINDEX] == NULL) || + (if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname) == NULL)) { + LOG(ERROR) << __func__ << " failed to get ifname"; + return false; + } + + auto event = dwpal_nl_to_bwl_event(gnlh->cmd); + + switch (event) { + case Event::Channel_Scan_Triggered: { + if (m_radio_info.iface_name.compare(ifname) != 0) { + // ifname doesn't match current interface + // meaning the event was recevied for a diffrent channel + return true; + } + LOG(DEBUG) << "DWPAL NL event channel scan triggered"; + + // Setting to distingwish from 1st and rest of NL80211_CMD_NEW_SCAN_RESULTS events. + // 1st event "empty dump result" need to send back scan dump request. + // rest of events are the actual scan dumps. + m_wait_for_channel_scan_results_ready = true; + event_queue_push(event); + break; + } + case Event::Channel_Scan_Dump_Result: { + if (m_radio_info.iface_name.compare(ifname) != 0) { + // ifname doesn't match current interface + // meaning the event was recevied for a diffrent channel + return true; + } + + if (m_wait_for_channel_scan_results_ready) { + if (m_nl_seq == 0 && nlh->nlmsg_seq != 0) { + LOG(DEBUG) << "Results dump are ready with sequence number: " + << (int)nlh->nlmsg_seq; + m_nl_seq = nlh->nlmsg_seq; + m_wait_for_channel_scan_results_ready = false; + } + + event_queue_push(Event::Channel_Scan_New_Results_Ready); + channel_scan_dump_results(); + break; + } + + LOG(DEBUG) << "DWPAL NL event channel scan results dump"; + + //TODO: Translate results from NL format to usable format + + event_queue_push(event); + break; + } + case Event::Channel_Scan_Abort: { + + if (m_radio_info.iface_name.compare(ifname) != 0) { + // ifname doesn't match current interface + // meaning the event was recevied for a diffrent channel + return true; + } + LOG(DEBUG) << "DWPAL NL event channel scan aborted"; + + m_nl_seq = 0; + m_wait_for_channel_scan_results_ready = false; + + event_queue_push(event); + break; + } + case Event::Channel_Scan_Finished: { + // ifname is corrupted for Channel_Scan_Finished event using nlh->nlmsg_seq instead. + if (nlh->nlmsg_seq != m_nl_seq) { + // Current event has a sequence number not matching the current sequence number + // meaning the event was recevied for a diffrent channel + return true; + } + + LOG(DEBUG) << "DWPAL NL event channel scan results finished for sequence: " + << (int)nlh->nlmsg_seq; + + m_nl_seq = 0; + m_wait_for_channel_scan_results_ready = false; + + event_queue_push(event); + break; + } + // Gracefully ignore unhandled events + default: + LOG(ERROR) << "Unknown DWPAL NL event received: " << int(event); + break; + } + return true; } } // namespace dwpal diff --git a/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.h b/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.h index 5c92c857a5..5572ef3015 100644 --- a/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.h +++ b/common/beerocks/bwl/dwpal/mon_wlan_hal_dwpal.h @@ -40,7 +40,9 @@ class mon_wlan_hal_dwpal : public base_wlan_hal_dwpal, public mon_wlan_hal { virtual bool sta_beacon_11k_request(const SBeaconRequest11k &req, int &dialog_token) override; virtual bool sta_statistics_11k_request(const SStatisticsRequest11k &req) override; virtual bool sta_link_measurements_11k_request(const std::string &sta_mac) override; - + virtual bool channel_scan_trigger(int dwell_time_msec, + const std::vector &channel_pool); + virtual bool channel_scan_dump_results(); // Protected methods: protected: virtual bool process_dwpal_event(char *buffer, int bufLen, const std::string &opcode) override; @@ -54,10 +56,67 @@ class mon_wlan_hal_dwpal : public base_wlan_hal_dwpal, public mon_wlan_hal { // Private data-members: private: + bool dwpal_get_scan_params_fg(sScanCfgParams ¶ms) + { + if (sizeof(params) != dwpal_nl_cmd_get(m_radio_info.iface_name, + LTQ_NL80211_VENDOR_SUBCMD_GET_SCAN_PARAMS, + m_nl_buffer, NL_MAX_REPLY_BUFFSIZE)) { + LOG(ERROR) << "LTQ_NL80211_VENDOR_SUBCMD_GET_SCAN_PARAMS failed! returned size does " + "not match sScanCfgParams!"; + return false; + } + + if (!memcpy_s(¶ms, sizeof(params), &m_nl_buffer[NL_ATTR_HDR], sizeof(params))) { + LOG(ERROR) << __func__ << " memcpy_s failed!"; + return false; + } + return true; + } + + bool dwpal_get_scan_params_bg(sScanCfgParamsBG ¶ms) + { + if (sizeof(params) != dwpal_nl_cmd_get(m_radio_info.iface_name, + LTQ_NL80211_VENDOR_SUBCMD_GET_SCAN_PARAMS_BG, + m_nl_buffer, NL_MAX_REPLY_BUFFSIZE)) { + LOG(ERROR) << "LTQ_NL80211_VENDOR_SUBCMD_GET_SCAN_PARAMS_BG failed! returned size does " + "not match sScanCfgParamsBG!"; + return false; + } + + if (!memcpy_s(¶ms, sizeof(params), &m_nl_buffer[NL_ATTR_HDR], sizeof(params))) { + LOG(ERROR) << __func__ << " memcpy_s failed!"; + return false; + } + return true; + } + + bool dwpal_set_scan_params_fg(const sScanCfgParams ¶ms) + { + if (dwpal_nl_cmd_set(m_radio_info.iface_name, LTQ_NL80211_VENDOR_SUBCMD_SET_SCAN_PARAMS, + (unsigned char *)¶ms, sizeof(params))) { + LOG(ERROR) << __func__ << " LTQ_NL80211_VENDOR_SUBCMD_SET_SCAN_PARAMS failed!"; + return false; + } + return true; + } + + bool dwpal_set_scan_params_bg(const sScanCfgParamsBG ¶ms) + { + if (dwpal_nl_cmd_set(m_radio_info.iface_name, LTQ_NL80211_VENDOR_SUBCMD_SET_SCAN_PARAMS_BG, + (unsigned char *)¶ms, sizeof(params))) { + LOG(ERROR) << __func__ << " LTQ_NL80211_VENDOR_SUBCMD_SET_SCAN_PARAMS_BG failed!"; + return false; + } + return true; + } + std::shared_ptr m_temp_dwpal_value; + bool m_wait_for_channel_scan_results_ready = false; + uint32_t m_nl_seq = 0; + unsigned char m_nl_buffer[NL_MAX_REPLY_BUFFSIZE] = {'\0'}; }; } // namespace dwpal } // namespace bwl -#endif // _BWL_MON_WLAN_HAL_DWPAL_H_ \ No newline at end of file +#endif // _BWL_MON_WLAN_HAL_DWPAL_H_ diff --git a/common/beerocks/bwl/include/bwl/mon_wlan_hal.h b/common/beerocks/bwl/include/bwl/mon_wlan_hal.h index 198da122f8..c4c68fed01 100644 --- a/common/beerocks/bwl/include/bwl/mon_wlan_hal.h +++ b/common/beerocks/bwl/include/bwl/mon_wlan_hal.h @@ -11,6 +11,7 @@ #include "base_wlan_hal.h" #include "mon_wlan_hal_types.h" +#include namespace bwl { @@ -32,7 +33,13 @@ class mon_wlan_hal : public virtual base_wlan_hal { RRM_Beacon_Request_Status, RRM_Beacon_Response, RRM_STA_Statistics_Response, - RRM_Link_Measurement_Response + RRM_Link_Measurement_Response, + //CHANNEL_SCAN events + Channel_Scan_Triggered, + Channel_Scan_New_Results_Ready, + Channel_Scan_Dump_Result, + Channel_Scan_Abort, + Channel_Scan_Finished }; // Public methods: