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 <xinrui.sun@broadcom.com>
This commit is contained in:
Xinrui Sun 2020-06-12 20:49:07 +08:00 committed by Jouni Malinen
parent 90d3ee383f
commit 61a258e784
7 changed files with 322 additions and 0 deletions

View file

@ -28,6 +28,9 @@ CONFIG_LIBNL20=y
# QCA vendor extensions to nl80211 # 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) # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y #CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include #CFLAGS += -I/usr/local/include

156
src/common/brcm_vendor.h Normal file
View file

@ -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 */

View file

@ -27,6 +27,7 @@
#include "eloop.h" #include "eloop.h"
#include "common/qca-vendor.h" #include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h" #include "common/qca-vendor-attr.h"
#include "common/brcm_vendor.h"
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h" #include "common/ieee802_11_common.h"
#include "common/wpa_common.h" #include "common/wpa_common.h"
@ -11605,6 +11606,60 @@ fail:
#endif /* CONFIG_DRIVER_NL80211_QCA */ #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) static int nl80211_write_to_file(const char *name, unsigned int val)
{ {
int fd, len; 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, .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow,
.add_sta_node = nl80211_add_sta_node, .add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */ #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, .configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab, .get_ext_capab = nl80211_get_ext_capab,
.update_connect_params = nl80211_update_connection_params, .update_connect_params = nl80211_update_connection_params,

View file

@ -16,6 +16,7 @@
#include "common/wpa_common.h" #include "common/wpa_common.h"
#include "common/qca-vendor.h" #include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h" #include "common/qca-vendor-attr.h"
#include "common/brcm_vendor.h"
#include "driver_nl80211.h" #include "driver_nl80211.h"
@ -1019,6 +1020,16 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
break; break;
#endif /* CONFIG_DRIVER_NL80211_QCA */ #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", wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",

View file

@ -15,6 +15,7 @@
#include "utils/eloop.h" #include "utils/eloop.h"
#include "common/qca-vendor.h" #include "common/qca-vendor.h"
#include "common/qca-vendor-attr.h" #include "common/qca-vendor-attr.h"
#include "common/brcm_vendor.h"
#include "common/ieee802_11_defs.h" #include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h" #include "common/ieee802_11_common.h"
#include "driver_nl80211.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, static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
struct nlattr **tb) struct nlattr **tb)
{ {
@ -2425,6 +2507,11 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
case OUI_QCA: case OUI_QCA:
nl80211_vendor_event_qca(drv, subcmd, data, len); nl80211_vendor_event_qca(drv, subcmd, data, len);
break; break;
#ifdef CONFIG_DRIVER_NL80211_BRCM
case OUI_BRCM:
nl80211_vendor_event_brcm(drv, subcmd, data, len);
break;
#endif /* CONFIG_DRIVER_NL80211_BRCM */
default: default:
wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
break; break;

View file

@ -26,6 +26,10 @@ NEED_LIBNL=y
CONFIG_LIBNL3_ROUTE=y CONFIG_LIBNL3_ROUTE=y
endif endif
ifdef CONFIG_DRIVER_NL80211_BRCM
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
endif
ifdef CONFIG_DRIVER_MACSEC_QCA ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o DRV_OBJS += ../src/drivers/driver_macsec_qca.o

View file

@ -41,6 +41,9 @@ DRV_OBJS += src/drivers/driver_nl80211_scan.c
ifdef CONFIG_DRIVER_NL80211_QCA ifdef CONFIG_DRIVER_NL80211_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_QCA
endif endif
ifdef CONFIG_DRIVER_NL80211_BRCM
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
endif
NEED_SME=y NEED_SME=y
NEED_AP_MLME=y NEED_AP_MLME=y
NEED_NETLINK=y NEED_NETLINK=y