diff mbox series

Add ACS support for broadcom device

Message ID 79a5e81af8f9b156b7f43fc4f82b22d0@mail.gmail.com
State Superseded
Headers show
Series Add ACS support for broadcom device | expand

Commit Message

Xinrui Sun June 12, 2020, 2:53 p.m. UTC
Hi,

This is the patch to add ACS support for Broadcom device. May I submit it
by this mail list?

Or could you help to share the steps to submit it?

Patch was created based on published source code. The details are:

From b9efc86587a14c0165dfda8ded5070703decc75b Mon Sep 17 00:00:00 2001
From: Xinrui Sun <xinrui.sun@broadcom.com>
Date: Fri, 12 Jun 2020 20:49:07 +0800
Subject: [PATCH] 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 <xinrui.sun@broadcom.com>
---
hostapd/android.config             |   5 +-
src/common/brcm_vendor.h           | 156 +++++++++++++++++++++++++++++
src/drivers/driver_nl80211.c       | 104 +++++++++++++++++++
src/drivers/driver_nl80211_capa.c  |  11 ++
src/drivers/driver_nl80211_event.c |  93 +++++++++++++++++
src/drivers/drivers.mak            |   4 +
src/drivers/drivers.mk             |   3 +
7 files changed, 375 insertions(+), 1 deletion(-)
create mode 100644 src/common/brcm_vendor.h

--
2.17.2


Thanks,
Xinrui.
diff mbox series

Patch

diff --git a/hostapd/android.config b/hostapd/android.config
index 94a9bb47b..34b42d389 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -26,7 +26,10 @@ 
CONFIG_LIBNL20=y

 # QCA vendor extensions to nl80211
-CONFIG_DRIVER_NL80211_QCA=y
+#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
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 72189da24..de9b4651f 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -38,6 +38,10 @@ 
#include "rfkill.h"
#include "driver_nl80211.h"

+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */
+

 #ifndef NETLINK_CAP_ACK
#define NETLINK_CAP_ACK 10
@@ -11212,6 +11216,103 @@  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 = 0;
+
+             do {
+                             freq_list_len =
int_array_len(params->freq_list);
+                             wpa_printf(MSG_DEBUG, "%s:
freq_list_len=%d",
+                                             __FUNCTION__,
freq_list_len);
+
+                             msg = nl80211_drv_msg(drv, 0,
NL80211_CMD_VENDOR);
+                             if (!msg) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, no memory for msg",
+
__FUNCTION__);
+                                             return ret;
+                             }
+                             if ((nla_put_u32(msg,
NL80211_ATTR_VENDOR_ID, OUI_BRCM))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, NL80211_ATTR_VENDOR_ID",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u32(msg,
NL80211_ATTR_VENDOR_SUBCMD, BRCM_VENDOR_SCMD_ACS))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, NL80211_ATTR_VENDOR_SUBCMD",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if (!(data = nla_nest_start(msg,
NL80211_ATTR_VENDOR_DATA))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, NL80211_ATTR_VENDOR_DATA",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u8(msg,
BRCM_VENDOR_ATTR_ACS_HW_MODE, params->hw_mode))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_HW_MODE",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u8(msg,
BRCM_VENDOR_ATTR_ACS_HT_ENABLED, params->ht_enabled))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_HT_ENABLED",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u8(msg,
BRCM_VENDOR_ATTR_ACS_HT40_ENABLED, params->ht40_enabled))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_HT40_ENABLED",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u8(msg,
BRCM_VENDOR_ATTR_ACS_VHT_ENABLED, params->vht_enabled))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_VHT_ENABLED",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             if ((nla_put_u16(msg,
BRCM_VENDOR_ATTR_ACS_CHWIDTH, params->ch_width))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_CHWIDTH",
+
__FUNCTION__);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+                             wpa_printf(MSG_DEBUG, "%s: ht40=%d,
ch_width=%d\n", __FUNCTION__,
+                                             params->ht40_enabled,
params->ch_width);
+                             if ((freq_list_len > 0)
+                                             && (nla_put(msg,
BRCM_VENDOR_ATTR_ACS_FREQ_LIST, sizeof(int) * freq_list_len,
+
    params->freq_list))) {
+                                             wpa_printf(MSG_ERROR, "%s:
*errof, BRCM_VENDOR_ATTR_ACS_FREQ_LIST, list_len=%d",
+
__FUNCTION__, freq_list_len);
+                                             nlmsg_free(msg);
+                                             return ret;
+                             }
+
+                             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);
+                             if (ret) {
+                                             wpa_printf(MSG_ERROR,
+                                                             "nl80211:
BRCM Failed to invoke driver ACS function: %s",
+
strerror(errno));
+                             }
+             } while (0);
+
+             return ret;
+}
+#endif /* CONFIG_DRIVER_NL80211_BRCM */

 static int nl80211_write_to_file(const char *name, unsigned int val)
{
@@ -11649,6 +11750,9 @@  const struct wpa_driver_ops wpa_driver_nl80211_ops
= {
               .set_bssid_blacklist = nl80211_set_bssid_blacklist,
               .add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
+#if defined(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 b9eb6e220..067bf96f0 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -18,6 +18,9 @@ 
#include "common/qca-vendor-attr.h"
#include "driver_nl80211.h"

+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif

 static int protocol_feature_handler(struct nl_msg *msg, void *arg)
{
@@ -991,6 +994,14 @@  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\n");
+                                                             }
+#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 6a2de1f3c..93ae11321 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -19,6 +19,9 @@ 
#include "common/ieee802_11_common.h"
#include "driver_nl80211.h"

+#ifdef CONFIG_DRIVER_NL80211_BRCM
+#include "common/brcm_vendor.h"
+#endif /* CONFIG_DRIVER_NL80211_BRCM */

 static const char * nl80211_command_to_string(enum nl80211_commands cmd)
{
@@ -2228,6 +2231,90 @@  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]);
+             }
+             wpa_printf(MSG_DEBUG, "got pri_freq=%d\n",
event.acs_selected_channels.pri_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]);
+             }
+             wpa_printf(MSG_DEBUG, "got sec_freq=%d\n",
event.acs_selected_channels.sec_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_INFO,
+                       "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)
+{
+             union wpa_event_data event;
+
+             wpa_printf(MSG_DEBUG, "got vendor event %d", subcmd);
+             memset(&event, 0, sizeof(event));
+             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:
+                             wpa_msg(NULL, MSG_INFO, "%s", data);
+                             brcm_nl80211_acs_select_ch(drv, data, len);
+                             break;
+
+             default:
+                             wpa_printf(MSG_ERROR, "%s-%d: Ignore
unsupported BRCM vendor event %u",
+                                        __FUNCTION__, __LINE__, subcmd);
+                             break;
+             }
+}
+
+#endif /* CONFIG_DRIVER_NL80211_BRCM */

 static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
                                                                struct
nlattr **tb)
@@ -2267,6 +2354,12 @@  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:
+                             wpa_printf(MSG_DEBUG, "BRCM event");
+                             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