mirror of
https://github.com/torvalds/linux.git
synced 2026-06-09 07:03:37 +02:00
net: wireless: bcmdhd: support Hotspot 2.0 release 1.0
Change-Id: I0d893b85741da628cb5c49c0a1b70c9d2d1ffac9 Signed-off-by: Ecco Park <eccopark@broadcom.com> Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
parent
23f01e8e81
commit
d0230ed8ab
|
|
@ -72,6 +72,7 @@ DHDCFLAGS += -DPROP_TXSTATUS_VSDB
|
|||
DHDCFLAGS += -DCUSTOM_MAX_TXGLOM_SIZE=32
|
||||
DHDCFLAGS += -DREPEAT_READFRAME
|
||||
DHDCFLAGS += -DROAM_AP_ENV_DETECTION
|
||||
DHDCFLAGS += -DWL11U
|
||||
else
|
||||
DHDCFLAGS += -DCUSTOM_SDIO_F2_BLKSIZE=128
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -67,6 +67,12 @@
|
|||
#include <dhd_wlfc.h>
|
||||
#endif
|
||||
|
||||
#ifdef WL11U
|
||||
#if !defined(WL_ENABLE_P2P_IF) && !defined(WL_CFG80211_P2P_DEV_IF)
|
||||
#error You should enable 'WL_ENABLE_P2P_IF' or 'WL_CFG80211_P2P_DEV_IF' \
|
||||
according to Kernel version and is supported only in Android-JB
|
||||
#endif /* !WL_ENABLE_P2P_IF && !WL_CFG80211_P2P_DEV_IF */
|
||||
#endif /* WL11U */
|
||||
|
||||
|
||||
#define IW_WSEC_ENABLED(wsec) ((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))
|
||||
|
|
@ -434,6 +440,13 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size);
|
|||
static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size);
|
||||
static u32 wl_get_ielen(struct wl_priv *wl);
|
||||
|
||||
#ifdef WL11U
|
||||
bcm_tlv_t *
|
||||
wl_cfg80211_find_interworking_ie(u8 *parse, u32 len);
|
||||
static s32
|
||||
wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
|
||||
uint8 ie_id, uint8 *data, uint8 data_len);
|
||||
#endif /* WL11U */
|
||||
|
||||
static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev, void *data);
|
||||
static void wl_free_wdev(struct wl_priv *wl);
|
||||
|
|
@ -2124,6 +2137,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
|||
bool iscan_req;
|
||||
bool escan_req = false;
|
||||
bool p2p_ssid;
|
||||
#ifdef WL11U
|
||||
bcm_tlv_t *interworking_ie;
|
||||
#endif
|
||||
s32 err = 0;
|
||||
s32 bssidx = -1;
|
||||
s32 i;
|
||||
|
|
@ -2232,6 +2248,29 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
|
|||
err = BCME_ERROR;
|
||||
goto scan_out;
|
||||
}
|
||||
#ifdef WL11U
|
||||
if ((interworking_ie = wl_cfg80211_find_interworking_ie(
|
||||
(u8 *)request->ie, request->ie_len)) != NULL) {
|
||||
err = wl_cfg80211_add_iw_ie(wl, ndev, bssidx,
|
||||
VNDR_IE_CUSTOM_FLAG, interworking_ie->id,
|
||||
interworking_ie->data, interworking_ie->len);
|
||||
|
||||
if (unlikely(err)) {
|
||||
goto scan_out;
|
||||
}
|
||||
} else if (wl->iw_ie_len != 0) {
|
||||
/* we have to clear IW IE and disable gratuitous APR */
|
||||
wl_cfg80211_add_iw_ie(wl, ndev, bssidx,
|
||||
VNDR_IE_CUSTOM_FLAG,
|
||||
DOT11_MNG_INTERWORKING_ID,
|
||||
0, 0);
|
||||
|
||||
wldev_iovar_setint_bsscfg(ndev, "grat_arp", 0,
|
||||
bssidx);
|
||||
wl->wl11u = FALSE;
|
||||
/* we don't care about error */
|
||||
}
|
||||
#endif /* WL11U */
|
||||
err = wl_cfgp2p_set_management_ie(wl, ndev, bssidx,
|
||||
VNDR_IE_PRBREQ_FLAG, (u8 *)request->ie,
|
||||
request->ie_len);
|
||||
|
|
@ -4671,12 +4710,50 @@ wl_cfg80211_config_p2p_pub_af_tx(struct wiphy *wiphy,
|
|||
return err;
|
||||
}
|
||||
|
||||
#ifdef WL11U
|
||||
static bool
|
||||
wl_cfg80211_check_DFS_channel(struct wl_priv *wl, wl_af_params_t *af_params,
|
||||
void *frame, u16 frame_len)
|
||||
{
|
||||
struct wl_scan_results *bss_list;
|
||||
struct wl_bss_info *bi = NULL;
|
||||
bool result = false;
|
||||
s32 i;
|
||||
|
||||
/* If DFS channel is 52~148, check to block it or not */
|
||||
if (af_params &&
|
||||
(af_params->channel >= 52 && af_params->channel <= 148)) {
|
||||
if (!wl_cfgp2p_is_p2p_action(frame, frame_len)) {
|
||||
bss_list = wl->bss_list;
|
||||
bi = next_bss(bss_list, bi);
|
||||
for_each_bss(bss_list, bi, i) {
|
||||
if (CHSPEC_IS5G(bi->chanspec) &&
|
||||
((bi->ctl_ch ? bi->ctl_ch : CHSPEC_CHANNEL(bi->chanspec))
|
||||
== af_params->channel)) {
|
||||
result = true; /* do not block the action frame */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
result = true;
|
||||
}
|
||||
|
||||
WL_DBG(("result=%s", result?"true":"false"));
|
||||
return result;
|
||||
}
|
||||
#endif /* WL11U */
|
||||
|
||||
|
||||
static bool
|
||||
wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
|
||||
bcm_struct_cfgdev *cfgdev, wl_af_params_t *af_params,
|
||||
wl_action_frame_t *action_frame, u16 action_frame_len, s32 bssidx)
|
||||
{
|
||||
#ifdef WL11U
|
||||
struct net_device *ndev = NULL;
|
||||
#endif /* WL11U */
|
||||
struct wl_priv *wl = wiphy_priv(wiphy);
|
||||
bool ack = false;
|
||||
u8 category, action;
|
||||
|
|
@ -4687,6 +4764,13 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
|
|||
#endif
|
||||
dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub);
|
||||
|
||||
#ifdef WL11U
|
||||
#if defined(WL_CFG80211_P2P_DEV_IF)
|
||||
ndev = dev;
|
||||
#else
|
||||
ndev = ndev_to_cfgdev(cfgdev);
|
||||
#endif /* WL_CFG80211_P2P_DEV_IF */
|
||||
#endif /* WL11U */
|
||||
|
||||
category = action_frame->data[DOT11_ACTION_CAT_OFF];
|
||||
action = action_frame->data[DOT11_ACTION_ACT_OFF];
|
||||
|
|
@ -4758,6 +4842,10 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
|
|||
} else {
|
||||
config_af_params.search_channel = false;
|
||||
}
|
||||
#ifdef WL11U
|
||||
if (ndev == wl_to_prmry_ndev(wl))
|
||||
config_af_params.search_channel = false;
|
||||
#endif /* WL11U */
|
||||
|
||||
#ifdef VSDB
|
||||
/* if connecting on primary iface, sleep for a while before sending af tx for VSDB */
|
||||
|
|
@ -4770,6 +4858,12 @@ wl_cfg80211_send_action_frame(struct wiphy *wiphy, struct net_device *dev,
|
|||
if (wl_get_drv_status_all(wl, SCANNING)) {
|
||||
wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true);
|
||||
}
|
||||
#ifdef WL11U
|
||||
/* handling DFS channel exceptions */
|
||||
if (!wl_cfg80211_check_DFS_channel(wl, af_params, action_frame->data, action_frame->len)) {
|
||||
return false; /* the action frame was blocked */
|
||||
}
|
||||
#endif /* WL11U */
|
||||
|
||||
/* set status and destination address before sending af */
|
||||
if (wl->next_af_subtype != P2P_PAF_SUBTYPE_INVALID) {
|
||||
|
|
@ -10926,6 +11020,100 @@ wl_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WL11U
|
||||
bcm_tlv_t *
|
||||
wl_cfg80211_find_interworking_ie(u8 *parse, u32 len)
|
||||
{
|
||||
bcm_tlv_t *ie;
|
||||
|
||||
while ((ie = bcm_parse_tlvs(parse, (u32)len, DOT11_MNG_INTERWORKING_ID))) {
|
||||
return (bcm_tlv_t *)ie;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static s32
|
||||
wl_cfg80211_add_iw_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag,
|
||||
uint8 ie_id, uint8 *data, uint8 data_len)
|
||||
{
|
||||
s32 err = BCME_OK;
|
||||
s32 buf_len;
|
||||
s32 iecount;
|
||||
ie_setbuf_t *ie_setbuf;
|
||||
|
||||
if (ie_id != DOT11_MNG_INTERWORKING_ID)
|
||||
return BCME_UNSUPPORTED;
|
||||
|
||||
/* Validate the pktflag parameter */
|
||||
if ((pktflag & ~(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG |
|
||||
VNDR_IE_ASSOCRSP_FLAG | VNDR_IE_AUTHRSP_FLAG |
|
||||
VNDR_IE_PRBREQ_FLAG | VNDR_IE_ASSOCREQ_FLAG|
|
||||
VNDR_IE_CUSTOM_FLAG))) {
|
||||
WL_ERR(("cfg80211 Add IE: Invalid packet flag 0x%x\n", pktflag));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* use VNDR_IE_CUSTOM_FLAG flags for none vendor IE . currently fixed value */
|
||||
pktflag = htod32(pktflag);
|
||||
|
||||
buf_len = sizeof(ie_setbuf_t) + data_len - 1;
|
||||
ie_setbuf = (ie_setbuf_t *) kzalloc(buf_len, GFP_KERNEL);
|
||||
|
||||
if (!ie_setbuf) {
|
||||
WL_ERR(("Error allocating buffer for IE\n"));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (wl->iw_ie_len == data_len && !memcmp(wl->iw_ie, data, data_len)) {
|
||||
WL_ERR(("Previous IW IE is equals to current IE\n"));
|
||||
err = BCME_OK;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
strncpy(ie_setbuf->cmd, "add", VNDR_IE_CMD_LEN - 1);
|
||||
ie_setbuf->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
|
||||
|
||||
/* Buffer contains only 1 IE */
|
||||
iecount = htod32(1);
|
||||
memcpy((void *)&ie_setbuf->ie_buffer.iecount, &iecount, sizeof(int));
|
||||
memcpy((void *)&ie_setbuf->ie_buffer.ie_list[0].pktflag, &pktflag, sizeof(uint32));
|
||||
|
||||
/* Now, add the IE to the buffer */
|
||||
ie_setbuf->ie_buffer.ie_list[0].ie_data.id = ie_id;
|
||||
|
||||
/* if already set with previous values, delete it first */
|
||||
if (wl->iw_ie_len != 0) {
|
||||
WL_DBG(("Different IW_IE was already set. clear first\n"));
|
||||
|
||||
ie_setbuf->ie_buffer.ie_list[0].ie_data.len = 0;
|
||||
|
||||
err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
|
||||
wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
|
||||
|
||||
if (err != BCME_OK)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ie_setbuf->ie_buffer.ie_list[0].ie_data.len = data_len;
|
||||
memcpy((uchar *)&ie_setbuf->ie_buffer.ie_list[0].ie_data.data[0], data, data_len);
|
||||
|
||||
err = wldev_iovar_setbuf_bsscfg(ndev, "ie", ie_setbuf, buf_len,
|
||||
wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync);
|
||||
|
||||
if (err == BCME_OK) {
|
||||
memcpy(wl->iw_ie, data, data_len);
|
||||
wl->iw_ie_len = data_len;
|
||||
wl->wl11u = TRUE;
|
||||
|
||||
err = wldev_iovar_setint_bsscfg(ndev, "grat_arp", 1, bssidx);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ie_setbuf)
|
||||
kfree(ie_setbuf);
|
||||
return err;
|
||||
}
|
||||
#endif /* WL11U */
|
||||
|
||||
static void wl_cfg80211_work_handler(struct work_struct * work)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -473,6 +473,13 @@ struct parsed_ies {
|
|||
|
||||
|
||||
|
||||
#ifdef WL11U
|
||||
/* Max length of Interworking element */
|
||||
#define IW_IES_MAX_BUF_LEN 9
|
||||
#endif
|
||||
#ifdef WLFBT
|
||||
#define FBT_KEYLEN 32
|
||||
#endif
|
||||
#define MAX_EVENT_BUF_NUM 16
|
||||
typedef struct wl_eventmsg_buf {
|
||||
u16 num;
|
||||
|
|
@ -573,6 +580,11 @@ struct wl_priv {
|
|||
struct net_info *_net_info, enum wl_status state, bool set);
|
||||
unsigned long interrested_state;
|
||||
wlc_ssid_t hostapd_ssid;
|
||||
#ifdef WL11U
|
||||
bool wl11u;
|
||||
u8 iw_ie[IW_IES_MAX_BUF_LEN];
|
||||
u32 iw_ie_len;
|
||||
#endif /* WL11U */
|
||||
bool sched_scan_running; /* scheduled scan req status */
|
||||
#ifdef WL_SCHED_SCAN
|
||||
struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */
|
||||
|
|
|
|||
|
|
@ -157,6 +157,26 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
|
|||
if (sd_act_frm->category != P2PSD_ACTION_CATEGORY)
|
||||
return false;
|
||||
|
||||
#ifdef WL11U
|
||||
/* XXX Hotspot2.0 STA mode can receive only response
|
||||
* SoftAP mode cannot run Hotspot2.0 compliant Ap because
|
||||
* Hotspot2.0 support only Enterprise mode
|
||||
*/
|
||||
if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP)
|
||||
return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
|
||||
(u8 *)sd_act_frm->query_data + GAS_RESP_OFFSET,
|
||||
frame_len);
|
||||
|
||||
else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP)
|
||||
return wl_cfgp2p_find_gas_subtype(P2PSD_GAS_OUI_SUBTYPE,
|
||||
(u8 *)sd_act_frm->query_data + GAS_CRESP_OFFSET,
|
||||
frame_len);
|
||||
else if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
|
||||
sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
#else
|
||||
if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ ||
|
||||
sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP ||
|
||||
sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ ||
|
||||
|
|
@ -164,6 +184,7 @@ bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len)
|
|||
return true;
|
||||
else
|
||||
return false;
|
||||
#endif /* WL11U */
|
||||
}
|
||||
void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len, u32 channel)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user