mirror of
https://github.com/Divested-Mobile/DivestOS-Build.git
synced 2024-10-01 01:35:54 -04:00
349 lines
12 KiB
Diff
349 lines
12 KiB
Diff
|
From e5c1b001a822e8b38680655c400e7b3f67cc3323 Mon Sep 17 00:00:00 2001
|
||
|
From: Insun Song <insun.song@broadcom.com>
|
||
|
Date: Thu, 10 Nov 2016 15:01:31 -0800
|
||
|
Subject: [PATCH] net: wireless: bcmdhd: fix buffer overrun in anqpo config
|
||
|
|
||
|
1. memory leak fix when input packet content corrupted.
|
||
|
2. reduced unnecessary debug messages
|
||
|
|
||
|
Signed-off-by: Insun Song <insun.song@broadcom.com>
|
||
|
Bug: 32219453
|
||
|
Change-Id: I0f79310c97571cd46afff29f58f66b17a2471927
|
||
|
---
|
||
|
drivers/net/wireless/bcmdhd/dhd_linux.c | 2 +
|
||
|
drivers/net/wireless/bcmdhd/dhd_pno.c | 3 +-
|
||
|
drivers/net/wireless/bcmdhd/dhd_pno.h | 17 ++--
|
||
|
drivers/net/wireless/bcmdhd/wl_cfg80211.c | 14 +++
|
||
|
drivers/net/wireless/bcmdhd/wl_cfgvendor.c | 141 ++++++++++++++++++++---------
|
||
|
5 files changed, 127 insertions(+), 50 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c
|
||
|
index 2fd2934a7e851..00201de5de5b8 100644
|
||
|
--- a/drivers/net/wireless/bcmdhd/dhd_linux.c
|
||
|
+++ b/drivers/net/wireless/bcmdhd/dhd_linux.c
|
||
|
@@ -8621,6 +8621,7 @@ int dhd_dev_set_whitelist_ssid(struct net_device *dev, wl_ssid_whitelist_t *ssid
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
void * dhd_dev_process_anqpo_result(struct net_device *dev,
|
||
|
const void *data, uint32 event, int *send_evt_bytes)
|
||
|
{
|
||
|
@@ -8628,6 +8629,7 @@ void * dhd_dev_process_anqpo_result(struct net_device *dev,
|
||
|
|
||
|
return (dhd_pno_process_anqpo_result(&dhd->pub, data, event, send_evt_bytes));
|
||
|
}
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
#endif /* GSCAN_SUPPORT */
|
||
|
|
||
|
int dhd_dev_set_rssi_monitor_cfg(struct net_device *dev, int start,
|
||
|
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.c b/drivers/net/wireless/bcmdhd/dhd_pno.c
|
||
|
index 8d6d234cd11b3..a88d1e2e41320 100644
|
||
|
--- a/drivers/net/wireless/bcmdhd/dhd_pno.c
|
||
|
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.c
|
||
|
@@ -3798,6 +3798,7 @@ dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data, uint32 event, int
|
||
|
return results;
|
||
|
}
|
||
|
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
void *
|
||
|
dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size)
|
||
|
{
|
||
|
@@ -3849,7 +3850,7 @@ dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
-
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
|
||
|
void *dhd_handle_hotlist_scan_evt(dhd_pub_t *dhd, const void *event_data, int *send_evt_bytes,
|
||
|
hotlist_type_t type)
|
||
|
diff --git a/drivers/net/wireless/bcmdhd/dhd_pno.h b/drivers/net/wireless/bcmdhd/dhd_pno.h
|
||
|
index b61d0fd866364..a0edf54049acf 100644
|
||
|
--- a/drivers/net/wireless/bcmdhd/dhd_pno.h
|
||
|
+++ b/drivers/net/wireless/bcmdhd/dhd_pno.h
|
||
|
@@ -98,8 +98,9 @@
|
||
|
|
||
|
#define CHANNEL_BUCKET_EMPTY_INDEX 0xFFFF
|
||
|
#define GSCAN_RETRY_THRESHOLD 3
|
||
|
-#define MAX_EPNO_SSID_NUM 64
|
||
|
-
|
||
|
+#define MAX_EPNO_SSID_NUM 64
|
||
|
+#define GSCAN_ANQPO_MAX_HS_LIST_SIZE 16
|
||
|
+#define ANQPO_MAX_HS_NAI_REALM_SIZE 256
|
||
|
#endif /* GSCAN_SUPPORT */
|
||
|
|
||
|
enum scan_status {
|
||
|
@@ -351,10 +352,10 @@ typedef struct gscan_results_cache {
|
||
|
} gscan_results_cache_t;
|
||
|
|
||
|
typedef struct {
|
||
|
- int id; /* identifier of this network block, report this in event */
|
||
|
- char realm[256]; /* null terminated UTF8 encoded realm, 0 if unspecified */
|
||
|
- int64_t roamingConsortiumIds[16]; /* roaming consortium ids to match, 0s if unspecified */
|
||
|
- uint8 plmn[3]; /* mcc/mnc combination as per rules, 0s if unspecified */
|
||
|
+ int id;
|
||
|
+ char realm[ANQPO_MAX_HS_NAI_REALM_SIZE];
|
||
|
+ int64_t roamingConsortiumIds[ANQPO_MAX_PFN_HS];
|
||
|
+ uint8 plmn[ANQPO_MCC_LENGTH];
|
||
|
} wifi_passpoint_network;
|
||
|
|
||
|
typedef struct dhd_pno_gscan_capabilities {
|
||
|
@@ -517,8 +518,10 @@ extern void dhd_dev_gscan_hotlist_cache_cleanup(struct net_device *dev, hotlist_
|
||
|
extern int dhd_dev_wait_batch_results_complete(struct net_device *dev);
|
||
|
extern void * dhd_dev_process_epno_result(struct net_device *dev,
|
||
|
const void *data, uint32 event, int *send_evt_bytes);
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
extern void * dhd_dev_process_anqpo_result(struct net_device *dev,
|
||
|
const void *data, uint32 event, int *send_evt_bytes);
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
extern int dhd_dev_set_epno(struct net_device *dev);
|
||
|
extern int dhd_dev_flush_fw_epno(struct net_device *dev);
|
||
|
#endif /* GSCAN_SUPPORT */
|
||
|
@@ -567,7 +570,9 @@ extern void dhd_gscan_hotlist_cache_cleanup(dhd_pub_t *dhd, hotlist_type_t type)
|
||
|
extern int dhd_wait_batch_results_complete(dhd_pub_t *dhd);
|
||
|
extern void * dhd_pno_process_epno_result(dhd_pub_t *dhd, const void *data,
|
||
|
uint32 event, int *size);
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
extern void * dhd_pno_process_anqpo_result(dhd_pub_t *dhd, const void *data, uint32 event, int *size);
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
extern void dhd_pno_translate_epno_fw_flags(uint32 *flags);
|
||
|
extern int dhd_pno_set_epno(dhd_pub_t *dhd);
|
||
|
extern int dhd_pno_flush_fw_epno(dhd_pub_t *dhd);
|
||
|
diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
|
||
|
index a56ba6b82e197..3d70a82adfa5e 100644
|
||
|
--- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c
|
||
|
+++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c
|
||
|
@@ -9423,6 +9423,16 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
|
||
|
} else
|
||
|
err = -ENOMEM;
|
||
|
break;
|
||
|
+ case WLC_E_PFN_SSID_EXT:
|
||
|
+ ptr = dhd_dev_process_epno_result(ndev, data, event, &send_evt_bytes);
|
||
|
+ if (ptr) {
|
||
|
+ wl_cfgvendor_send_async_event(wiphy, ndev,
|
||
|
+ GOOGLE_SCAN_EPNO_EVENT, ptr, send_evt_bytes);
|
||
|
+ kfree(ptr);
|
||
|
+ } else
|
||
|
+ err = -ENOMEM;
|
||
|
+ break;
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
case WLC_E_PFN_NET_FOUND:
|
||
|
ptr = dhd_dev_process_anqpo_result(ndev, data, event, &len);
|
||
|
if (ptr) {
|
||
|
@@ -9432,6 +9442,7 @@ wl_notify_gscan_event(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev,
|
||
|
} else
|
||
|
err = -ENOMEM;
|
||
|
break;
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
default:
|
||
|
WL_ERR(("Unknown event %d\n", event));
|
||
|
break;
|
||
|
@@ -10035,7 +10046,10 @@ static void wl_init_event_handler(struct bcm_cfg80211 *cfg)
|
||
|
cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event;
|
||
|
cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event;
|
||
|
cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event;
|
||
|
+ cfg->evt_handler[WLC_E_PFN_SSID_EXT] = wl_notify_gscan_event;
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
cfg->evt_handler[WLC_E_GAS_FRAGMENT_RX] = wl_notify_gscan_event;
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
cfg->evt_handler[WLC_E_ROAM_EXP_EVENT] = wl_handle_roam_exp_event;
|
||
|
#endif /* GSCAN_SUPPORT */
|
||
|
cfg->evt_handler[WLC_E_RSSI_LQM] = wl_handle_rssi_monitor_event;
|
||
|
diff --git a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
|
||
|
index 5be16a72aa43f..b156660ed053a 100644
|
||
|
--- a/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
|
||
|
+++ b/drivers/net/wireless/bcmdhd/wl_cfgvendor.c
|
||
|
@@ -939,10 +939,13 @@ static int wl_cfgvendor_epno_cfg(struct wiphy *wiphy,
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
|
||
|
struct wireless_dev *wdev, const void *data, int len)
|
||
|
{
|
||
|
- int err = BCME_ERROR, rem, type, hs_list_size = 0, malloc_size, i = 0, j, k, num_oi, oi_len;
|
||
|
+ int err = BCME_ERROR, rem, type, malloc_size, i = 0;
|
||
|
+ uint32 hs_list_size = 0;
|
||
|
+ int j, k, num_oi, oi_len;
|
||
|
wifi_passpoint_network *hs_list = NULL, *src_hs;
|
||
|
wl_anqpo_pfn_hs_list_t *anqpo_hs_list;
|
||
|
wl_anqpo_pfn_hs_t *dst_hs;
|
||
|
@@ -953,52 +956,100 @@ static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
|
||
|
char *rcid;
|
||
|
|
||
|
nla_for_each_attr(iter, data, len, rem) {
|
||
|
- type = nla_type(iter);
|
||
|
- switch (type) {
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_LIST:
|
||
|
- if (hs_list_size > 0) {
|
||
|
- hs_list = kmalloc(hs_list_size*sizeof(wifi_passpoint_network), GFP_KERNEL);
|
||
|
- if (hs_list == NULL) {
|
||
|
- WL_ERR(("failed to allocate hs_list\n"));
|
||
|
- return -ENOMEM;
|
||
|
- }
|
||
|
- }
|
||
|
- nla_for_each_nested(outer, iter, tmp) {
|
||
|
- nla_for_each_nested(inner, outer, tmp1) {
|
||
|
- type = nla_type(inner);
|
||
|
+ type = nla_type(iter);
|
||
|
+ switch (type) {
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_LIST:
|
||
|
+ if (hs_list) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ if (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ if (hs_list_size > 0) {
|
||
|
+ hs_list = kzalloc(hs_list_size *
|
||
|
+ sizeof(wifi_passpoint_network), GFP_KERNEL);
|
||
|
+ if (!hs_list) {
|
||
|
+ WL_ERR(("failed to allocate hs_list\n"));
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ nla_for_each_nested(outer, iter, tmp) {
|
||
|
+ if (i == hs_list_size)
|
||
|
+ break;
|
||
|
+ nla_for_each_nested(inner, outer, tmp1) {
|
||
|
+ type = nla_type(inner);
|
||
|
|
||
|
- switch (type) {
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID:
|
||
|
- hs_list[i].id = nla_get_u32(inner);
|
||
|
- WL_ERR(("%s: net id: %d\n", __func__, hs_list[i].id));
|
||
|
- break;
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM:
|
||
|
- memcpy(hs_list[i].realm,
|
||
|
- nla_data(inner), 256);
|
||
|
- WL_ERR(("%s: realm: %s\n", __func__, hs_list[i].realm));
|
||
|
- break;
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID:
|
||
|
- memcpy(hs_list[i].roamingConsortiumIds,
|
||
|
- nla_data(inner), 128);
|
||
|
- break;
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN:
|
||
|
- memcpy(hs_list[i].plmn,
|
||
|
- nla_data(inner), 3);
|
||
|
- WL_ERR(("%s: plmn: %c %c %c\n", __func__, hs_list[i].plmn[0], hs_list[i].plmn[1], hs_list[i].plmn[2]));
|
||
|
- break;
|
||
|
- }
|
||
|
- }
|
||
|
- i++;
|
||
|
+ switch (type) {
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_NETWORK_ID:
|
||
|
+ if (nla_len(inner) != sizeof(hs_list[i].id)) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
}
|
||
|
+ hs_list[i].id = nla_get_u32(inner);
|
||
|
+ WL_DBG(("%s: net id: %d\n",
|
||
|
+ __func__, hs_list[i].id));
|
||
|
break;
|
||
|
- case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE:
|
||
|
- hs_list_size = nla_get_u32(iter);
|
||
|
- WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size));
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_NAI_REALM:
|
||
|
+ if (nla_len(inner) !=
|
||
|
+ sizeof(hs_list[i].realm)) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ memcpy(hs_list[i].realm, nla_data(inner),
|
||
|
+ sizeof(hs_list[i].realm));
|
||
|
+ WL_DBG(("%s: realm: %s\n",
|
||
|
+ __func__, hs_list[i].realm));
|
||
|
break;
|
||
|
- default:
|
||
|
- WL_ERR(("Unknown type: %d\n", type));
|
||
|
- return err;
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_ROAM_CONSORTIUM_ID:
|
||
|
+ if (nla_len(inner) != sizeof(hs_list[i].
|
||
|
+ roamingConsortiumIds)) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ memcpy(hs_list[i].roamingConsortiumIds,
|
||
|
+ nla_data(inner),
|
||
|
+ sizeof(hs_list[i].roamingConsortiumIds));
|
||
|
+ break;
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_PLMN:
|
||
|
+ if (nla_len(inner) != sizeof(hs_list[i].plmn)) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ memcpy(hs_list[i].plmn,
|
||
|
+ nla_data(inner),
|
||
|
+ sizeof(hs_list[i].plmn));
|
||
|
+ WL_DBG(("%s: plmn: %c %c %c\n",
|
||
|
+ __func__, hs_list[i].plmn[0],
|
||
|
+ hs_list[i].plmn[1],
|
||
|
+ hs_list[i].plmn[2]));
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ i++;
|
||
|
}
|
||
|
+ break;
|
||
|
+ case GSCAN_ATTRIBUTE_ANQPO_HS_LIST_SIZE:
|
||
|
+ if (nla_len(iter) != sizeof(hs_list_size)) {
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ hs_list_size = nla_get_u32(iter);
|
||
|
+ if ((hs_list_size == 0) ||
|
||
|
+ (hs_list_size > GSCAN_ANQPO_MAX_HS_LIST_SIZE)) {
|
||
|
+ WL_ERR(("%s: ANQPO: %d\n", __func__, hs_list_size));
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+ WL_DBG(("%s: ANQPO: %d\n", __func__, hs_list_size));
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ WL_ERR(("Unknown type: %d\n", type));
|
||
|
+ err = -EINVAL;
|
||
|
+ goto exit;
|
||
|
+ }
|
||
|
+
|
||
|
}
|
||
|
|
||
|
malloc_size = OFFSETOF(wl_anqpo_pfn_hs_list_t, hs) +
|
||
|
@@ -1046,7 +1097,7 @@ static int wl_cfgvendor_gscan_anqpo_config(struct wiphy *wiphy,
|
||
|
kfree(hs_list);
|
||
|
return err;
|
||
|
}
|
||
|
-
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
static int wl_cfgvendor_set_batch_scan_cfg(struct wiphy *wiphy,
|
||
|
struct wireless_dev *wdev, const void *data, int len)
|
||
|
{
|
||
|
@@ -3065,6 +3116,7 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = {
|
||
|
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
|
||
|
.doit = wl_cfgvendor_set_bssid_blacklist
|
||
|
},
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
{
|
||
|
{
|
||
|
.vendor_id = OUI_GOOGLE,
|
||
|
@@ -3073,6 +3125,7 @@ static const struct wiphy_vendor_command wl_vendor_cmds [] = {
|
||
|
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,
|
||
|
.doit = wl_cfgvendor_gscan_anqpo_config
|
||
|
},
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
#endif /* GSCAN_SUPPORT */
|
||
|
{
|
||
|
{
|
||
|
@@ -3233,7 +3286,9 @@ static const struct nl80211_vendor_cmd_info wl_vendor_events [] = {
|
||
|
{ OUI_GOOGLE, GOOGLE_SCAN_EPNO_EVENT },
|
||
|
{ OUI_GOOGLE, GOOGLE_DEBUG_RING_EVENT },
|
||
|
{ OUI_GOOGLE, GOOGLE_FW_DUMP_EVENT },
|
||
|
+#ifdef DHD_ANQPO_SUPPORT
|
||
|
{ OUI_GOOGLE, GOOGLE_PNO_HOTSPOT_FOUND_EVENT },
|
||
|
+#endif /* DHD_ANQPO_SUPPORT */
|
||
|
{ OUI_GOOGLE, GOOGLE_RSSI_MONITOR_EVENT },
|
||
|
{ OUI_GOOGLE, GOOGLE_MKEEP_ALIVE_EVENT }
|
||
|
};
|