From 61a258e784fbe5acc689e709a98ae773703c0412 Mon Sep 17 00:00:00 2001 From: Xinrui Sun Date: Fri, 12 Jun 2020 20:49:07 +0800 Subject: [PATCH] nl80211: Add ACS support for Broadcom device BRCM vendor command used to trigger ACS scan. After ACS finished, DHD driver will send results by event BRCM_VENDOR_EVENT_ACS. Signed-off-by: Xinrui Sun --- hostapd/android.config | 3 + src/common/brcm_vendor.h | 156 +++++++++++++++++++++++++++++ src/drivers/driver_nl80211.c | 58 +++++++++++ src/drivers/driver_nl80211_capa.c | 11 ++ src/drivers/driver_nl80211_event.c | 87 ++++++++++++++++ src/drivers/drivers.mak | 4 + src/drivers/drivers.mk | 3 + 7 files changed, 322 insertions(+) create mode 100644 src/common/brcm_vendor.h diff --git a/hostapd/android.config b/hostapd/android.config index 7bd792efe..c8b3afabe 100644 --- a/hostapd/android.config +++ b/hostapd/android.config @@ -28,6 +28,9 @@ CONFIG_LIBNL20=y # QCA vendor extensions to nl80211 CONFIG_DRIVER_NL80211_QCA=y +# Broadcom vendor extensions to nl80211 +#CONFIG_DRIVER_NL80211_BRCM=y + # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver) #CONFIG_DRIVER_BSD=y #CFLAGS += -I/usr/local/include diff --git a/src/common/brcm_vendor.h b/src/common/brcm_vendor.h new file mode 100644 index 000000000..f163dea73 --- /dev/null +++ b/src/common/brcm_vendor.h @@ -0,0 +1,156 @@ +/* + * Broadcom Corporation OUI and vendor specific assignments + * Copyright (c) 2020, Broadcom Corporation. + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef BRCM_VENDOR_H +#define BRCM_VENDOR_H + +/* + * This file is a registry of identifier assignments from the Broadcom + * OUI 00:10:18 for purposes other than MAC address assignment. New identifiers + * can be assigned through normal review process for changes to the upstream + * hostap.git repository. + */ + +#define OUI_BRCM 0x001018 + +/** + * enum brcm_nl80211_vendor_subcmds - BRCM nl80211 vendor command identifiers + * + * @BRCM_VENDOR_SCMD_UNSPEC: Reserved value 0 + * + * @BRCM_VENDOR_SCMD_PRIV_STR: Provide vendor private cmds to send to FW. + * + * @BRCM_VENDOR_SCMD_BCM_STR: Provide vendor cmds to BCMDHD driver. + * + * @BRCM_VENDOR_SCMD_BCM_PSK: Used to set SAE password. + * + * @BRCM_VENDOR_SCMD_SET_PMK: Command to check driver support + * for DFS offloading. + * + * @BRCM_VENDOR_SCMD_GET_FEATURES: Command to get the features + * supported by the driver. + * + * @BRCM_VENDOR_SCMD_SET_MAC: Set random mac address for P2P interface. + * + * @BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS: Set some connect parameters. + * Used for the case that FW handle SAE. + * + * @BRCM_VENDOR_SCMD_SET_START_AP_PARAMS: Set SoftAP paramters. + * Used for the case that FW handle SAE. + * + * @BRCM_VENDOR_SCMD_ACS: ACS command/event which is used to + * invoke the ACS function in device and pass selected channels to + * hostapd. Uses enum qca_wlan_vendor_attr_acs_offload attributes. + * + * @BRCM_VENDOR_SCMD_MAX: This acts as a the tail of cmds list. + * Make sure it located at the end of the list. + * + */ +enum brcm_nl80211_vendor_subcmds { + BRCM_VENDOR_SCMD_UNSPEC = 0, + BRCM_VENDOR_SCMD_PRIV_STR = 1, + BRCM_VENDOR_SCMD_BCM_STR = 2, + BRCM_VENDOR_SCMD_BCM_PSK = 3, + BRCM_VENDOR_SCMD_SET_PMK = 4, + BRCM_VENDOR_SCMD_GET_FEATURES = 5, + BRCM_VENDOR_SCMD_SET_MAC = 6, + BRCM_VENDOR_SCMD_SET_CONNECT_PARAMS = 7, + BRCM_VENDOR_SCMD_SET_START_AP_PARAMS = 8, + BRCM_VENDOR_SCMD_ACS = 9, + BRCM_VENDOR_SCMD_MAX = 10 +}; + +/** + * enum brcm_nl80211_vendor_events - BRCM nl80211 asynchoronous event identifiers + * + * @BRCM_VENDOR_EVENT_UNSPEC: Reserved value 0 + * + * @BRCM_VENDOR_EVENT_PRIV_STR: String command/event + */ +enum brcm_nl80211_vendor_events { + BRCM_VENDOR_EVENT_UNSPEC = 0, + BRCM_VENDOR_EVENT_PRIV_STR = 1, + GOOGLE_GSCAN_SIGNIFICANT_EVENT = 2, + GOOGLE_GSCAN_GEOFENCE_FOUND_EVENT = 3, + GOOGLE_GSCAN_BATCH_SCAN_EVENT = 4, + GOOGLE_SCAN_FULL_RESULTS_EVENT = 5, + GOOGLE_RTT_COMPLETE_EVENT = 6, + GOOGLE_SCAN_COMPLETE_EVENT = 7, + GOOGLE_GSCAN_GEOFENCE_LOST_EVENT = 8, + GOOGLE_SCAN_EPNO_EVENT = 9, + GOOGLE_DEBUG_RING_EVENT = 10, + GOOGLE_FW_DUMP_EVENT = 11, + GOOGLE_PNO_HOTSPOT_FOUND_EVENT = 12, + GOOGLE_RSSI_MONITOR_EVENT = 13, + GOOGLE_MKEEP_ALIVE_EVENT = 14, + + /* + * BRCM specific events should be placed after + * the Generic events so that enums don't mismatch + * between the DHD and HAL + */ + GOOGLE_NAN_EVENT_ENABLED = 15, + GOOGLE_NAN_EVENT_DISABLED = 16, + GOOGLE_NAN_EVENT_SUBSCRIBE_MATCH = 17, + GOOGLE_NAN_EVENT_REPLIED = 18, + GOOGLE_NAN_EVENT_PUBLISH_TERMINATED = 19, + GOOGLE_NAN_EVENT_SUBSCRIBE_TERMINATED = 20, + GOOGLE_NAN_EVENT_DE_EVENT = 21, + GOOGLE_NAN_EVENT_FOLLOWUP = 22, + GOOGLE_NAN_EVENT_TRANSMIT_FOLLOWUP_IND = 23, + GOOGLE_NAN_EVENT_DATA_REQUEST = 24, + GOOGLE_NAN_EVENT_DATA_CONFIRMATION = 25, + GOOGLE_NAN_EVENT_DATA_END = 26, + GOOGLE_NAN_EVENT_BEACON = 27, + GOOGLE_NAN_EVENT_SDF = 28, + GOOGLE_NAN_EVENT_TCA = 29, + GOOGLE_NAN_EVENT_SUBSCRIBE_UNMATCH = 30, + GOOGLE_NAN_EVENT_UNKNOWN = 31, + GOOGLE_ROAM_EVENT_START = 32, + BRCM_VENDOR_EVENT_HANGED = 33, + BRCM_VENDOR_EVENT_SAE_KEY = 34, + BRCM_VENDOR_EVENT_BEACON_RECV = 35, + BRCM_VENDOR_EVENT_PORT_AUTHORIZED = 36, + GOOGLE_FILE_DUMP_EVENT = 37, + BRCM_VENDOR_EVENT_CU = 38, + BRCM_VENDOR_EVENT_WIPS = 39, + NAN_ASYNC_RESPONSE_DISABLED = 40, + BRCM_VENDOR_EVENT_RCC_INFO = 41, + BRCM_VENDOR_EVENT_ACS = 42, + BRCM_VENDOR_EVENT_LAST + +}; + +#ifdef CONFIG_BRCM_SAE +enum wifi_sae_key_attr { + BRCM_SAE_KEY_ATTR_BSSID, + BRCM_SAE_KEY_ATTR_PMK, + BRCM_SAE_KEY_ATTR_PMKID +}; +#endif /* CONFIG_BRCM_SAE */ + +enum wl_vendor_attr_acs_offload { + BRCM_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, + BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ, + BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ, + BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + + BRCM_VENDOR_ATTR_ACS_HW_MODE, + BRCM_VENDOR_ATTR_ACS_HT_ENABLED, + BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, + BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, + BRCM_VENDOR_ATTR_ACS_CHWIDTH, + BRCM_VENDOR_ATTR_ACS_CH_LIST, + BRCM_VENDOR_ATTR_ACS_FREQ_LIST, + + BRCM_VENDOR_ATTR_ACS_LAST +}; + + +#endif /* BRCM_VENDOR_H */ diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 8342eb8a9..59052a94e 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -27,6 +27,7 @@ #include "eloop.h" #include "common/qca-vendor.h" #include "common/qca-vendor-attr.h" +#include "common/brcm_vendor.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_common.h" @@ -11605,6 +11606,60 @@ fail: #endif /* CONFIG_DRIVER_NL80211_QCA */ +#ifdef CONFIG_DRIVER_NL80211_BRCM +static int wpa_driver_do_broadcom_acs(void *priv, struct drv_acs_params *params) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *data; + int freq_list_len; + int ret = -1; + + freq_list_len = int_array_len(params->freq_list); + wpa_printf(MSG_DEBUG, "%s: freq_list_len=%d", + __func__, freq_list_len); + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR); + if (!msg || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_BRCM) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + BRCM_VENDOR_SCMD_ACS) || + !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) || + nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode) || + nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT_ENABLED, + params->ht_enabled) || + nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, + params->ht40_enabled) || + nla_put_u8(msg, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, + params->vht_enabled) || + nla_put_u16(msg, BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width) || + (freq_list_len > 0 && + nla_put(msg, BRCM_VENDOR_ATTR_ACS_FREQ_LIST, + sizeof(int) * freq_list_len, params->freq_list))) + goto fail; + nla_nest_end(msg, data); + + wpa_printf(MSG_DEBUG, + "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d", + params->hw_mode, params->ht_enabled, params->ht40_enabled, + params->vht_enabled, params->ch_width); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: BRCM Failed to invoke driver ACS function: %s", + strerror(errno)); + } + + msg = NULL; +fail: + nlmsg_free(msg); + return ret; +} +#endif /* CONFIG_DRIVER_NL80211_BRCM */ + + static int nl80211_write_to_file(const char *name, unsigned int val) { int fd, len; @@ -12050,6 +12105,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow, .add_sta_node = nl80211_add_sta_node, #endif /* CONFIG_DRIVER_NL80211_QCA */ +#ifdef CONFIG_DRIVER_NL80211_BRCM + .do_acs = wpa_driver_do_broadcom_acs, +#endif /* CONFIG_DRIVER_NL80211_BRCM */ .configure_data_frame_filters = nl80211_configure_data_frame_filters, .get_ext_capab = nl80211_get_ext_capab, .update_connect_params = nl80211_update_connection_params, diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 1b57c0e88..7dac62b4e 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -16,6 +16,7 @@ #include "common/wpa_common.h" #include "common/qca-vendor.h" #include "common/qca-vendor-attr.h" +#include "common/brcm_vendor.h" #include "driver_nl80211.h" @@ -1019,6 +1020,16 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } +#ifdef CONFIG_DRIVER_NL80211_BRCM + } else if (vinfo->vendor_id == OUI_BRCM) { + switch (vinfo->subcmd) { + case BRCM_VENDOR_SCMD_ACS: + drv->capa.flags |= + WPA_DRIVER_FLAGS_ACS_OFFLOAD; + wpa_printf(MSG_DEBUG, + "Enabled BRCM ACS"); + } +#endif /* CONFIG_DRIVER_NL80211_BRCM */ } wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index c971001ae..c6f3e0ef6 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -15,6 +15,7 @@ #include "utils/eloop.h" #include "common/qca-vendor.h" #include "common/qca-vendor-attr.h" +#include "common/brcm_vendor.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "driver_nl80211.h" @@ -2381,6 +2382,87 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, } +#ifdef CONFIG_DRIVER_NL80211_BRCM + +static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, + const u8 *data, size_t len) +{ + struct nlattr *tb[BRCM_VENDOR_ATTR_ACS_LAST + 1]; + union wpa_event_data event; + + wpa_printf(MSG_DEBUG, + "nl80211: BRCM ACS channel selection vendor event received"); + + if (nla_parse(tb, BRCM_VENDOR_ATTR_ACS_LAST, (struct nlattr *) data, + len, NULL) || + !tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ] || + !tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]) + return; + + os_memset(&event, 0, sizeof(event)); + if (tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]) + event.acs_selected_channels.pri_freq = + nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_PRIMARY_FREQ]); + if (tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]) + event.acs_selected_channels.sec_freq = + nla_get_u32(tb[BRCM_VENDOR_ATTR_ACS_SECONDARY_FREQ]); + if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) + event.acs_selected_channels.vht_seg0_center_ch = + nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]); + if (tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]) + event.acs_selected_channels.vht_seg1_center_ch = + nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]); + if (tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]) + event.acs_selected_channels.ch_width = + nla_get_u16(tb[BRCM_VENDOR_ATTR_ACS_CHWIDTH]); + if (tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]) { + event.acs_selected_channels.hw_mode = nla_get_u8(tb[BRCM_VENDOR_ATTR_ACS_HW_MODE]); + if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES || + event.acs_selected_channels.hw_mode == + HOSTAPD_MODE_IEEE80211ANY) { + wpa_printf(MSG_DEBUG, + "nl80211: Invalid hw_mode %d in ACS selection event", + event.acs_selected_channels.hw_mode); + return; + } + } + + wpa_printf(MSG_DEBUG, + "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d", + event.acs_selected_channels.pri_freq, + event.acs_selected_channels.sec_freq, + event.acs_selected_channels.ch_width, + event.acs_selected_channels.vht_seg0_center_ch, + event.acs_selected_channels.vht_seg1_center_ch, + event.acs_selected_channels.hw_mode); + wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event); +} + + +static void nl80211_vendor_event_brcm(struct wpa_driver_nl80211_data *drv, + u32 subcmd, u8 *data, size_t len) +{ + wpa_printf(MSG_DEBUG, "nl80211: Got BRCM vendor event %u", subcmd); + switch (subcmd) { + case BRCM_VENDOR_EVENT_PRIV_STR: + case BRCM_VENDOR_EVENT_HANGED: + /* Dump the event on to the console */ + wpa_msg(NULL, MSG_INFO, "%s", data); + break; + case BRCM_VENDOR_EVENT_ACS: + brcm_nl80211_acs_select_ch(drv, data, len); + break; + default: + wpa_printf(MSG_DEBUG, + "%s: Ignore unsupported BRCM vendor event %u", + __func__, subcmd); + break; + } +} + +#endif /* CONFIG_DRIVER_NL80211_BRCM */ + + static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, struct nlattr **tb) { @@ -2425,6 +2507,11 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, case OUI_QCA: nl80211_vendor_event_qca(drv, subcmd, data, len); break; +#ifdef CONFIG_DRIVER_NL80211_BRCM + case OUI_BRCM: + nl80211_vendor_event_brcm(drv, subcmd, data, len); + break; +#endif /* CONFIG_DRIVER_NL80211_BRCM */ default: wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); break; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index 55a98ef86..a03d4a034 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -26,6 +26,10 @@ NEED_LIBNL=y CONFIG_LIBNL3_ROUTE=y endif +ifdef CONFIG_DRIVER_NL80211_BRCM +DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM +endif + ifdef CONFIG_DRIVER_MACSEC_QCA DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA DRV_OBJS += ../src/drivers/driver_macsec_qca.o diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index 5a32a2422..10eab6a92 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -41,6 +41,9 @@ DRV_OBJS += src/drivers/driver_nl80211_scan.c ifdef CONFIG_DRIVER_NL80211_QCA DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA endif +ifdef CONFIG_DRIVER_NL80211_BRCM +DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM +endif NEED_SME=y NEED_AP_MLME=y NEED_NETLINK=y