Commit 5419f7f1 authored by Hante Meuleman's avatar Hante Meuleman Committed by Kalle Valo

brcmfmac: Reshuffle functions to avoid forward declarations

Function prototype forward declarations are to be avoided. This
patch shuffles some of the functions so the forward declarations
can be removed.
Reviewed-by: default avatarArend Van Spriel <arend@broadcom.com>
Reviewed-by: default avatarPieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: default avatarHante Meuleman <meuleman@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 3021ad9a
...@@ -238,18 +238,6 @@ struct parsed_vndr_ies { ...@@ -238,18 +238,6 @@ struct parsed_vndr_ies {
struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT]; struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
}; };
/* Function prototype forward declarations */
static int
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_sched_scan_request *request);
static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
struct net_device *ndev);
static s32
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data);
static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf, static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
struct cfg80211_chan_def *ch) struct cfg80211_chan_def *ch)
{ {
...@@ -3081,717 +3069,713 @@ static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg) ...@@ -3081,717 +3069,713 @@ static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
brcmf_cfg80211_escan_timeout_worker); brcmf_cfg80211_escan_timeout_worker);
} }
static __always_inline void brcmf_delay(u32 ms) /* PFN result doesn't have all the info which are required by the supplicant
{ * (For e.g IEs) Do a target Escan so that sched scan results are reported
if (ms < 1000 / HZ) { * via wl_inform_single_bss in the required format. Escan does require the
cond_resched(); * scan request in the form of cfg80211_scan_request. For timebeing, create
mdelay(ms); * cfg80211_scan_request one out of the received PNO event.
} else { */
msleep(ms);
}
}
static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
u8 *pattern, u32 patternsize, u8 *mask,
u32 packet_offset)
{
struct brcmf_fil_wowl_pattern_le *filter;
u32 masksize;
u32 patternoffset;
u8 *buf;
u32 bufsize;
s32 ret;
masksize = (patternsize + 7) / 8;
patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
bufsize = sizeof(*filter) + patternsize + masksize;
buf = kzalloc(bufsize, GFP_KERNEL);
if (!buf)
return -ENOMEM;
filter = (struct brcmf_fil_wowl_pattern_le *)buf;
memcpy(filter->cmd, cmd, 4);
filter->masksize = cpu_to_le32(masksize);
filter->offset = cpu_to_le32(packet_offset);
filter->patternoffset = cpu_to_le32(patternoffset);
filter->patternsize = cpu_to_le32(patternsize);
filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
if ((mask) && (masksize))
memcpy(buf + sizeof(*filter), mask, masksize);
if ((pattern) && (patternsize))
memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
kfree(buf);
return ret;
}
static s32 static s32
brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
void *data) const struct brcmf_event_msg *e, void *data)
{ {
struct brcmf_cfg80211_info *cfg = ifp->drvr->config; struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
struct cfg80211_scan_request *request = NULL;
struct cfg80211_ssid *ssid = NULL;
struct ieee80211_channel *channel = NULL;
struct wiphy *wiphy = cfg_to_wiphy(cfg);
int err = 0;
int channel_req = 0;
int band = 0;
struct brcmf_pno_scanresults_le *pfn_result; struct brcmf_pno_scanresults_le *pfn_result;
struct brcmf_pno_net_info_le *netinfo; u32 result_count;
u32 status;
brcmf_dbg(SCAN, "Enter\n"); brcmf_dbg(SCAN, "Enter\n");
pfn_result = (struct brcmf_pno_scanresults_le *)data;
if (e->event_code == BRCMF_E_PFN_NET_LOST) { if (e->event_code == BRCMF_E_PFN_NET_LOST) {
brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n"); brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
return 0; return 0;
} }
if (le32_to_cpu(pfn_result->count) < 1) { pfn_result = (struct brcmf_pno_scanresults_le *)data;
brcmf_err("Invalid result count, expected 1 (%d)\n", result_count = le32_to_cpu(pfn_result->count);
le32_to_cpu(pfn_result->count)); status = le32_to_cpu(pfn_result->status);
return -EINVAL;
}
data += sizeof(struct brcmf_pno_scanresults_le); /* PFN event is limited to fit 512 bytes so we may get
netinfo = (struct brcmf_pno_net_info_le *)data; * multiple NET_FOUND events. For now place a warning here.
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len); */
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len; WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE);
cfg->wowl.nd->n_channels = 1; brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
cfg->wowl.nd->channels[0] = if (result_count > 0) {
ieee80211_channel_to_frequency(netinfo->channel, int i;
netinfo->channel <= CH_MAX_2G_CHANNEL ?
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
cfg->wowl.nd_info->n_matches = 1;
cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
/* Inform (the resume task) that the net detect information was recvd */ request = kzalloc(sizeof(*request), GFP_KERNEL);
cfg->wowl.nd_data_completed = true; ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
wake_up(&cfg->wowl.nd_data_wait); channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
if (!request || !ssid || !channel) {
err = -ENOMEM;
goto out_err;
}
return 0; request->wiphy = wiphy;
} data += sizeof(struct brcmf_pno_scanresults_le);
netinfo_start = (struct brcmf_pno_net_info_le *)data;
#ifdef CONFIG_PM for (i = 0; i < result_count; i++) {
netinfo = &netinfo_start[i];
if (!netinfo) {
brcmf_err("Invalid netinfo ptr. index: %d\n",
i);
err = -EINVAL;
goto out_err;
}
static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp) brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
{ netinfo->SSID, netinfo->channel);
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
struct brcmf_wowl_wakeind_le wake_ind_le; ssid[i].ssid_len = netinfo->SSID_len;
struct cfg80211_wowlan_wakeup wakeup_data; request->n_ssids++;
struct cfg80211_wowlan_wakeup *wakeup;
u32 wakeind;
s32 err;
int timeout;
err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le, channel_req = netinfo->channel;
sizeof(wake_ind_le)); if (channel_req <= CH_MAX_2G_CHANNEL)
if (err) { band = NL80211_BAND_2GHZ;
brcmf_err("Get wowl_wakeind failed, err = %d\n", err); else
return; band = NL80211_BAND_5GHZ;
channel[i].center_freq =
ieee80211_channel_to_frequency(channel_req,
band);
channel[i].band = band;
channel[i].flags |= IEEE80211_CHAN_NO_HT40;
request->channels[i] = &channel[i];
request->n_channels++;
} }
wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind); /* assign parsed ssid array */
if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | if (request->n_ssids)
BRCMF_WOWL_RETR | BRCMF_WOWL_NET | request->ssids = &ssid[0];
BRCMF_WOWL_PFN_FOUND)) {
wakeup = &wakeup_data;
memset(&wakeup_data, 0, sizeof(wakeup_data));
wakeup_data.pattern_idx = -1;
if (wakeind & BRCMF_WOWL_MAGIC) { if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n"); /* Abort any on-going scan */
wakeup_data.magic_pkt = true; brcmf_abort_scanning(cfg);
}
if (wakeind & BRCMF_WOWL_DIS) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_BCN) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_RETR) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_NET) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
/* For now always map to pattern 0, no API to get
* correct information available at the moment.
*/
wakeup_data.pattern_idx = 0;
} }
if (wakeind & BRCMF_WOWL_PFN_FOUND) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n"); set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
timeout = wait_event_timeout(cfg->wowl.nd_data_wait, cfg->escan_info.run = brcmf_run_escan;
cfg->wowl.nd_data_completed, err = brcmf_do_escan(cfg, wiphy, ifp, request);
BRCMF_ND_INFO_TIMEOUT); if (err) {
if (!timeout) clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
brcmf_err("No result for wowl net detect\n"); goto out_err;
else
wakeup_data.net_detect = cfg->wowl.nd_info;
} }
cfg->sched_escan = true;
cfg->scan_request = request;
} else { } else {
wakeup = NULL; brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
goto out_err;
} }
cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
}
#else kfree(ssid);
kfree(channel);
kfree(request);
return 0;
static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp) out_err:
{ kfree(ssid);
kfree(channel);
kfree(request);
cfg80211_sched_scan_stopped(wiphy);
return err;
} }
#endif /* CONFIG_PM */ static int brcmf_dev_pno_clean(struct net_device *ndev)
static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); int ret;
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
brcmf_dbg(TRACE, "Enter\n"); /* Disable pfn */
ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
if (ret == 0) {
/* clear pfn */
ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear",
NULL, 0);
}
if (ret < 0)
brcmf_err("failed code %d\n", ret);
if (cfg->wowl.active) { return ret;
brcmf_report_wowl_wakeind(wiphy, ifp);
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
brcmf_configure_arp_offload(ifp, true);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
cfg->wowl.pre_pmmode);
cfg->wowl.active = false;
if (cfg->wowl.nd_enabled) {
brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_notify_sched_scan_results);
cfg->wowl.nd_enabled = false;
}
}
return 0;
} }
static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg, static int brcmf_dev_pno_config(struct brcmf_if *ifp,
struct brcmf_if *ifp, struct cfg80211_sched_scan_request *request)
struct cfg80211_wowlan *wowl)
{ {
u32 wowl_config; struct brcmf_pno_param_le pfn_param;
u32 i; struct brcmf_pno_macaddr_le pfn_mac;
s32 err;
u8 *mac_mask;
int i;
brcmf_dbg(TRACE, "Suspend, wowl config.\n"); memset(&pfn_param, 0, sizeof(pfn_param));
pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
brcmf_configure_arp_offload(ifp, false); /* set extra pno params */
brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode); pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX); pfn_param.repeat = BRCMF_PNO_REPEAT;
pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX;
wowl_config = 0; /* set up pno scan fr */
if (wowl->disconnect) pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME);
wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
if (wowl->magic_pkt) err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param,
wowl_config |= BRCMF_WOWL_MAGIC; sizeof(pfn_param));
if ((wowl->patterns) && (wowl->n_patterns)) { if (err) {
wowl_config |= BRCMF_WOWL_NET; brcmf_err("pfn_set failed, err=%d\n", err);
for (i = 0; i < wowl->n_patterns; i++) { return err;
brcmf_config_wowl_pattern(ifp, "add",
(u8 *)wowl->patterns[i].pattern,
wowl->patterns[i].pattern_len,
(u8 *)wowl->patterns[i].mask,
wowl->patterns[i].pkt_offset);
}
} }
if (wowl->nd_config) {
brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
wowl->nd_config);
wowl_config |= BRCMF_WOWL_PFN_FOUND;
cfg->wowl.nd_data_completed = false; /* Find out if mac randomization should be turned on */
cfg->wowl.nd_enabled = true; if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR))
/* Now reroute the event for PFN to the wowl function. */ return 0;
brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND, pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
brcmf_wowl_nd_results); pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC;
memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN);
mac_mask = request->mac_addr_mask;
for (i = 0; i < ETH_ALEN; i++) {
pfn_mac.mac[i] &= mac_mask[i];
pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
} }
if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state)) /* Clear multi bit */
wowl_config |= BRCMF_WOWL_UNASSOC; pfn_mac.mac[0] &= 0xFE;
/* Set locally administered */
pfn_mac.mac[0] |= 0x02;
brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear")); err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac,
brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config); sizeof(pfn_mac));
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1); if (err)
brcmf_bus_wowl_config(cfg->pub->bus_if, true); brcmf_err("pfn_macaddr failed, err=%d\n", err);
cfg->wowl.active = true;
return err;
} }
static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, static int
struct cfg80211_wowlan *wowl) brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct net_device *ndev,
struct cfg80211_sched_scan_request *request)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_pno_net_param_le pfn;
int i;
int ret = 0;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n",
request->n_match_sets, request->n_ssids);
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
return -EAGAIN;
}
if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
brcmf_err("Scanning suppressed: status (%lu)\n",
cfg->scan_status);
return -EAGAIN;
}
/* if the primary net_device is not READY there is nothing if (!request->n_ssids || !request->n_match_sets) {
* we can do but pray resume goes smoothly. brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n",
request->n_ssids);
return -EINVAL;
}
if (request->n_ssids > 0) {
for (i = 0; i < request->n_ssids; i++) {
/* Active scan req for ssids */
brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n",
request->ssids[i].ssid);
/* match_set ssids is a supert set of n_ssid list,
* so we need not add these set separately.
*/ */
if (!check_vif_up(ifp->vif)) }
goto exit; }
/* Stop scheduled scan */ if (request->n_match_sets > 0) {
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) /* clean up everything */
brcmf_cfg80211_sched_scan_stop(wiphy, ndev); ret = brcmf_dev_pno_clean(ndev);
if (ret < 0) {
brcmf_err("failed error=%d\n", ret);
return ret;
}
/* end any scanning */ /* configure pno */
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) if (brcmf_dev_pno_config(ifp, request))
brcmf_abort_scanning(cfg); return -EINVAL;
if (wowl == NULL) { /* configure each match set */
brcmf_bus_wowl_config(cfg->pub->bus_if, false); for (i = 0; i < request->n_match_sets; i++) {
list_for_each_entry(vif, &cfg->vif_list, list) { struct cfg80211_ssid *ssid;
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state)) u32 ssid_len;
ssid = &request->match_sets[i].ssid;
ssid_len = ssid->ssid_len;
if (!ssid_len) {
brcmf_err("skip broadcast ssid\n");
continue; continue;
/* While going to suspend if associated with AP
* disassociate from AP to save power while system is
* in suspended state
*/
brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
* generated due to DISASSOC call to the fw to keep
* the state fw and WPA_Supplicant state consistent
*/
brcmf_delay(500);
} }
/* Configure MPC */ pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
brcmf_set_mpc(ifp, 1); pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY);
pfn.wsec = cpu_to_le32(0);
pfn.infra = cpu_to_le32(1);
pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT);
pfn.ssid.SSID_len = cpu_to_le32(ssid_len);
memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
sizeof(pfn));
brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
ret == 0 ? "set" : "failed", ssid->ssid);
}
/* Enable the PNO */
if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
brcmf_err("PNO enable failed!! ret=%d\n", ret);
return -EINVAL;
}
} else { } else {
/* Configure WOWL paramaters */ return -EINVAL;
brcmf_configure_wowl(cfg, ifp, wowl);
} }
exit:
brcmf_dbg(TRACE, "Exit\n");
/* clear any scanning activity */
cfg->scan_status = 0;
return 0; return 0;
} }
static __used s32 static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp) struct net_device *ndev)
{ {
struct brcmf_pmk_list_le *pmk_list; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
int i;
u32 npmk;
s32 err;
pmk_list = &cfg->pmk_list;
npmk = le32_to_cpu(pmk_list->npmk);
brcmf_dbg(CONN, "No of elements %d\n", npmk);
for (i = 0; i < npmk; i++)
brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list, brcmf_dbg(SCAN, "enter\n");
sizeof(*pmk_list)); brcmf_dev_pno_clean(ndev);
if (cfg->sched_escan)
brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
return 0;
}
return err; static __always_inline void brcmf_delay(u32 ms)
{
if (ms < 1000 / HZ) {
cond_resched();
mdelay(ms);
} else {
msleep(ms);
}
} }
static s32 static s32 brcmf_config_wowl_pattern(struct brcmf_if *ifp, u8 cmd[4],
brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, u8 *pattern, u32 patternsize, u8 *mask,
struct cfg80211_pmksa *pmksa) u32 packet_offset)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_fil_wowl_pattern_le *filter;
struct brcmf_if *ifp = netdev_priv(ndev); u32 masksize;
struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; u32 patternoffset;
s32 err; u8 *buf;
u32 npmk, i; u32 bufsize;
s32 ret;
brcmf_dbg(TRACE, "Enter\n"); masksize = (patternsize + 7) / 8;
if (!check_vif_up(ifp->vif)) patternoffset = sizeof(*filter) - sizeof(filter->cmd) + masksize;
return -EIO;
npmk = le32_to_cpu(cfg->pmk_list.npmk); bufsize = sizeof(*filter) + patternsize + masksize;
for (i = 0; i < npmk; i++) buf = kzalloc(bufsize, GFP_KERNEL);
if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN)) if (!buf)
break; return -ENOMEM;
if (i < BRCMF_MAXPMKID) { filter = (struct brcmf_fil_wowl_pattern_le *)buf;
memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
if (i == npmk) {
npmk++;
cfg->pmk_list.npmk = cpu_to_le32(npmk);
}
} else {
brcmf_err("Too many PMKSA entries cached %d\n", npmk);
return -EINVAL;
}
brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid); memcpy(filter->cmd, cmd, 4);
for (i = 0; i < WLAN_PMKID_LEN; i += 4) filter->masksize = cpu_to_le32(masksize);
brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i], filter->offset = cpu_to_le32(packet_offset);
pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2], filter->patternoffset = cpu_to_le32(patternoffset);
pmk[npmk].pmkid[i + 3]); filter->patternsize = cpu_to_le32(patternsize);
filter->type = cpu_to_le32(BRCMF_WOWL_PATTERN_TYPE_BITMAP);
err = brcmf_update_pmklist(cfg, ifp); if ((mask) && (masksize))
memcpy(buf + sizeof(*filter), mask, masksize);
if ((pattern) && (patternsize))
memcpy(buf + sizeof(*filter) + masksize, pattern, patternsize);
brcmf_dbg(TRACE, "Exit\n"); ret = brcmf_fil_iovar_data_set(ifp, "wowl_pattern", buf, bufsize);
return err;
kfree(buf);
return ret;
} }
static s32 static s32
brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
struct cfg80211_pmksa *pmksa) void *data)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_pno_scanresults_le *pfn_result;
struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0]; struct brcmf_pno_net_info_le *netinfo;
s32 err;
u32 npmk, i;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif))
return -EIO;
brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid); brcmf_dbg(SCAN, "Enter\n");
npmk = le32_to_cpu(cfg->pmk_list.npmk); pfn_result = (struct brcmf_pno_scanresults_le *)data;
for (i = 0; i < npmk; i++)
if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
break;
if ((npmk > 0) && (i < npmk)) { if (e->event_code == BRCMF_E_PFN_NET_LOST) {
for (; i < (npmk - 1); i++) { brcmf_dbg(SCAN, "PFN NET LOST event. Ignore\n");
memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN); return 0;
memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
WLAN_PMKID_LEN);
} }
memset(&pmk[i], 0, sizeof(*pmk));
cfg->pmk_list.npmk = cpu_to_le32(npmk - 1); if (le32_to_cpu(pfn_result->count) < 1) {
} else { brcmf_err("Invalid result count, expected 1 (%d)\n",
brcmf_err("Cache entry not found\n"); le32_to_cpu(pfn_result->count));
return -EINVAL; return -EINVAL;
} }
err = brcmf_update_pmklist(cfg, ifp); data += sizeof(struct brcmf_pno_scanresults_le);
netinfo = (struct brcmf_pno_net_info_le *)data;
memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
cfg->wowl.nd->n_channels = 1;
cfg->wowl.nd->channels[0] =
ieee80211_channel_to_frequency(netinfo->channel,
netinfo->channel <= CH_MAX_2G_CHANNEL ?
NL80211_BAND_2GHZ : NL80211_BAND_5GHZ);
cfg->wowl.nd_info->n_matches = 1;
cfg->wowl.nd_info->matches[0] = cfg->wowl.nd;
brcmf_dbg(TRACE, "Exit\n"); /* Inform (the resume task) that the net detect information was recvd */
return err; cfg->wowl.nd_data_completed = true;
wake_up(&cfg->wowl.nd_data_wait);
return 0;
} }
static s32 #ifdef CONFIG_PM
brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_wowl_wakeind_le wake_ind_le;
struct cfg80211_wowlan_wakeup wakeup_data;
struct cfg80211_wowlan_wakeup *wakeup;
u32 wakeind;
s32 err; s32 err;
int timeout;
brcmf_dbg(TRACE, "Enter\n"); err = brcmf_fil_iovar_data_get(ifp, "wowl_wakeind", &wake_ind_le,
if (!check_vif_up(ifp->vif)) sizeof(wake_ind_le));
return -EIO; if (err) {
brcmf_err("Get wowl_wakeind failed, err = %d\n", err);
memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list)); return;
err = brcmf_update_pmklist(cfg, ifp);
brcmf_dbg(TRACE, "Exit\n");
return err;
}
/*
* PFN result doesn't have all the info which are
* required by the supplicant
* (For e.g IEs) Do a target Escan so that sched scan results are reported
* via wl_inform_single_bss in the required format. Escan does require the
* scan request in the form of cfg80211_scan_request. For timebeing, create
* cfg80211_scan_request one out of the received PNO event.
*/
static s32
brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
const struct brcmf_event_msg *e, void *data)
{
struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
struct cfg80211_scan_request *request = NULL;
struct cfg80211_ssid *ssid = NULL;
struct ieee80211_channel *channel = NULL;
struct wiphy *wiphy = cfg_to_wiphy(cfg);
int err = 0;
int channel_req = 0;
int band = 0;
struct brcmf_pno_scanresults_le *pfn_result;
u32 result_count;
u32 status;
brcmf_dbg(SCAN, "Enter\n");
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
return 0;
} }
pfn_result = (struct brcmf_pno_scanresults_le *)data; wakeind = le32_to_cpu(wake_ind_le.ucode_wakeind);
result_count = le32_to_cpu(pfn_result->count); if (wakeind & (BRCMF_WOWL_MAGIC | BRCMF_WOWL_DIS | BRCMF_WOWL_BCN |
status = le32_to_cpu(pfn_result->status); BRCMF_WOWL_RETR | BRCMF_WOWL_NET |
BRCMF_WOWL_PFN_FOUND)) {
wakeup = &wakeup_data;
memset(&wakeup_data, 0, sizeof(wakeup_data));
wakeup_data.pattern_idx = -1;
/* if (wakeind & BRCMF_WOWL_MAGIC) {
* PFN event is limited to fit 512 bytes so we may get brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_MAGIC\n");
* multiple NET_FOUND events. For now place a warning here. wakeup_data.magic_pkt = true;
}
if (wakeind & BRCMF_WOWL_DIS) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_DIS\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_BCN) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_BCN\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_RETR) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_RETR\n");
wakeup_data.disconnect = true;
}
if (wakeind & BRCMF_WOWL_NET) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_NET\n");
/* For now always map to pattern 0, no API to get
* correct information available at the moment.
*/ */
WARN_ON(status != BRCMF_PNO_SCAN_COMPLETE); wakeup_data.pattern_idx = 0;
brcmf_dbg(SCAN, "PFN NET FOUND event. count: %d\n", result_count);
if (result_count > 0) {
int i;
request = kzalloc(sizeof(*request), GFP_KERNEL);
ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
if (!request || !ssid || !channel) {
err = -ENOMEM;
goto out_err;
} }
if (wakeind & BRCMF_WOWL_PFN_FOUND) {
request->wiphy = wiphy; brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_PFN_FOUND\n");
data += sizeof(struct brcmf_pno_scanresults_le); timeout = wait_event_timeout(cfg->wowl.nd_data_wait,
netinfo_start = (struct brcmf_pno_net_info_le *)data; cfg->wowl.nd_data_completed,
BRCMF_ND_INFO_TIMEOUT);
for (i = 0; i < result_count; i++) { if (!timeout)
netinfo = &netinfo_start[i]; brcmf_err("No result for wowl net detect\n");
if (!netinfo) { else
brcmf_err("Invalid netinfo ptr. index: %d\n", wakeup_data.net_detect = cfg->wowl.nd_info;
i); }
err = -EINVAL; } else {
goto out_err; wakeup = NULL;
} }
cfg80211_report_wowlan_wakeup(&ifp->vif->wdev, wakeup, GFP_KERNEL);
}
brcmf_dbg(SCAN, "SSID:%s Channel:%d\n", #else
netinfo->SSID, netinfo->channel);
memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
ssid[i].ssid_len = netinfo->SSID_len;
request->n_ssids++;
channel_req = netinfo->channel; static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
if (channel_req <= CH_MAX_2G_CHANNEL) {
band = NL80211_BAND_2GHZ; }
else
band = NL80211_BAND_5GHZ;
channel[i].center_freq =
ieee80211_channel_to_frequency(channel_req,
band);
channel[i].band = band;
channel[i].flags |= IEEE80211_CHAN_NO_HT40;
request->channels[i] = &channel[i];
request->n_channels++;
}
/* assign parsed ssid array */ #endif /* CONFIG_PM */
if (request->n_ssids)
request->ssids = &ssid[0];
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
/* Abort any on-going scan */ {
brcmf_abort_scanning(cfg); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
} struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); brcmf_dbg(TRACE, "Enter\n");
cfg->escan_info.run = brcmf_run_escan;
err = brcmf_do_escan(cfg, wiphy, ifp, request); if (cfg->wowl.active) {
if (err) { brcmf_report_wowl_wakeind(wiphy, ifp);
clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status); brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
goto out_err; brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
brcmf_configure_arp_offload(ifp, true);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
cfg->wowl.pre_pmmode);
cfg->wowl.active = false;
if (cfg->wowl.nd_enabled) {
brcmf_cfg80211_sched_scan_stop(cfg->wiphy, ifp->ndev);
brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_notify_sched_scan_results);
cfg->wowl.nd_enabled = false;
} }
cfg->sched_escan = true;
cfg->scan_request = request;
} else {
brcmf_err("FALSE PNO Event. (pfn_count == 0)\n");
goto out_err;
} }
kfree(ssid);
kfree(channel);
kfree(request);
return 0; return 0;
out_err:
kfree(ssid);
kfree(channel);
kfree(request);
cfg80211_sched_scan_stopped(wiphy);
return err;
} }
static int brcmf_dev_pno_clean(struct net_device *ndev) static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp,
struct cfg80211_wowlan *wowl)
{ {
int ret; u32 wowl_config;
u32 i;
/* Disable pfn */ brcmf_dbg(TRACE, "Suspend, wowl config.\n");
ret = brcmf_fil_iovar_int_set(netdev_priv(ndev), "pfn", 0);
if (ret == 0) { brcmf_configure_arp_offload(ifp, false);
/* clear pfn */ brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
ret = brcmf_fil_iovar_data_set(netdev_priv(ndev), "pfnclear", brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
NULL, 0);
wowl_config = 0;
if (wowl->disconnect)
wowl_config = BRCMF_WOWL_DIS | BRCMF_WOWL_BCN | BRCMF_WOWL_RETR;
if (wowl->magic_pkt)
wowl_config |= BRCMF_WOWL_MAGIC;
if ((wowl->patterns) && (wowl->n_patterns)) {
wowl_config |= BRCMF_WOWL_NET;
for (i = 0; i < wowl->n_patterns; i++) {
brcmf_config_wowl_pattern(ifp, "add",
(u8 *)wowl->patterns[i].pattern,
wowl->patterns[i].pattern_len,
(u8 *)wowl->patterns[i].mask,
wowl->patterns[i].pkt_offset);
} }
if (ret < 0) }
brcmf_err("failed code %d\n", ret); if (wowl->nd_config) {
brcmf_cfg80211_sched_scan_start(cfg->wiphy, ifp->ndev,
wowl->nd_config);
wowl_config |= BRCMF_WOWL_PFN_FOUND;
return ret; cfg->wowl.nd_data_completed = false;
cfg->wowl.nd_enabled = true;
/* Now reroute the event for PFN to the wowl function. */
brcmf_fweh_unregister(cfg->pub, BRCMF_E_PFN_NET_FOUND);
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_wowl_nd_results);
}
if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
wowl_config |= BRCMF_WOWL_UNASSOC;
brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
brcmf_bus_wowl_config(cfg->pub->bus_if, true);
cfg->wowl.active = true;
} }
static int brcmf_dev_pno_config(struct brcmf_if *ifp, static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
struct cfg80211_sched_scan_request *request) struct cfg80211_wowlan *wowl)
{ {
struct brcmf_pno_param_le pfn_param; struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_pno_macaddr_le pfn_mac; struct net_device *ndev = cfg_to_ndev(cfg);
s32 err; struct brcmf_if *ifp = netdev_priv(ndev);
u8 *mac_mask; struct brcmf_cfg80211_vif *vif;
int i;
memset(&pfn_param, 0, sizeof(pfn_param)); brcmf_dbg(TRACE, "Enter\n");
pfn_param.version = cpu_to_le32(BRCMF_PNO_VERSION);
/* set extra pno params */ /* if the primary net_device is not READY there is nothing
pfn_param.flags = cpu_to_le16(1 << BRCMF_PNO_ENABLE_ADAPTSCAN_BIT); * we can do but pray resume goes smoothly.
pfn_param.repeat = BRCMF_PNO_REPEAT; */
pfn_param.exp = BRCMF_PNO_FREQ_EXPO_MAX; if (!check_vif_up(ifp->vif))
goto exit;
/* set up pno scan fr */ /* Stop scheduled scan */
pfn_param.scan_freq = cpu_to_le32(BRCMF_PNO_TIME); if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO))
brcmf_cfg80211_sched_scan_stop(wiphy, ndev);
err = brcmf_fil_iovar_data_set(ifp, "pfn_set", &pfn_param, /* end any scanning */
sizeof(pfn_param)); if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status))
if (err) { brcmf_abort_scanning(cfg);
brcmf_err("pfn_set failed, err=%d\n", err);
return err; if (wowl == NULL) {
brcmf_bus_wowl_config(cfg->pub->bus_if, false);
list_for_each_entry(vif, &cfg->vif_list, list) {
if (!test_bit(BRCMF_VIF_STATUS_READY, &vif->sme_state))
continue;
/* While going to suspend if associated with AP
* disassociate from AP to save power while system is
* in suspended state
*/
brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
* generated due to DISASSOC call to the fw to keep
* the state fw and WPA_Supplicant state consistent
*/
brcmf_delay(500);
} }
/* Configure MPC */
brcmf_set_mpc(ifp, 1);
/* Find out if mac randomization should be turned on */ } else {
if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) /* Configure WOWL paramaters */
brcmf_configure_wowl(cfg, ifp, wowl);
}
exit:
brcmf_dbg(TRACE, "Exit\n");
/* clear any scanning activity */
cfg->scan_status = 0;
return 0; return 0;
}
pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; static __used s32
pfn_mac.flags = BRCMF_PFN_MAC_OUI_ONLY | BRCMF_PFN_SET_MAC_UNASSOC; brcmf_update_pmklist(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp)
{
struct brcmf_pmk_list_le *pmk_list;
int i;
u32 npmk;
s32 err;
memcpy(pfn_mac.mac, request->mac_addr, ETH_ALEN); pmk_list = &cfg->pmk_list;
mac_mask = request->mac_addr_mask; npmk = le32_to_cpu(pmk_list->npmk);
for (i = 0; i < ETH_ALEN; i++) {
pfn_mac.mac[i] &= mac_mask[i];
pfn_mac.mac[i] |= get_random_int() & ~(mac_mask[i]);
}
/* Clear multi bit */
pfn_mac.mac[0] &= 0xFE;
/* Set locally administered */
pfn_mac.mac[0] |= 0x02;
err = brcmf_fil_iovar_data_set(ifp, "pfn_macaddr", &pfn_mac, brcmf_dbg(CONN, "No of elements %d\n", npmk);
sizeof(pfn_mac)); for (i = 0; i < npmk; i++)
if (err) brcmf_dbg(CONN, "PMK[%d]: %pM\n", i, &pmk_list->pmk[i].bssid);
brcmf_err("pfn_macaddr failed, err=%d\n", err);
err = brcmf_fil_iovar_data_set(ifp, "pmkid_info", pmk_list,
sizeof(*pmk_list));
return err; return err;
} }
static int static s32
brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev,
struct net_device *ndev, struct cfg80211_pmksa *pmksa)
struct cfg80211_sched_scan_request *request)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
struct brcmf_pno_net_param_le pfn; s32 err;
int i; u32 npmk, i;
int ret = 0;
brcmf_dbg(SCAN, "Enter n_match_sets:%d n_ssids:%d\n", brcmf_dbg(TRACE, "Enter\n");
request->n_match_sets, request->n_ssids); if (!check_vif_up(ifp->vif))
if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) { return -EIO;
brcmf_err("Scanning already: status (%lu)\n", cfg->scan_status);
return -EAGAIN;
}
if (test_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status)) {
brcmf_err("Scanning suppressed: status (%lu)\n",
cfg->scan_status);
return -EAGAIN;
}
if (!request->n_ssids || !request->n_match_sets) { npmk = le32_to_cpu(cfg->pmk_list.npmk);
brcmf_dbg(SCAN, "Invalid sched scan req!! n_ssids:%d\n", for (i = 0; i < npmk; i++)
request->n_ssids); if (!memcmp(pmksa->bssid, pmk[i].bssid, ETH_ALEN))
break;
if (i < BRCMF_MAXPMKID) {
memcpy(pmk[i].bssid, pmksa->bssid, ETH_ALEN);
memcpy(pmk[i].pmkid, pmksa->pmkid, WLAN_PMKID_LEN);
if (i == npmk) {
npmk++;
cfg->pmk_list.npmk = cpu_to_le32(npmk);
}
} else {
brcmf_err("Too many PMKSA entries cached %d\n", npmk);
return -EINVAL; return -EINVAL;
} }
if (request->n_ssids > 0) { brcmf_dbg(CONN, "set_pmksa - PMK bssid: %pM =\n", pmk[npmk].bssid);
for (i = 0; i < request->n_ssids; i++) { for (i = 0; i < WLAN_PMKID_LEN; i += 4)
/* Active scan req for ssids */ brcmf_dbg(CONN, "%02x %02x %02x %02x\n", pmk[npmk].pmkid[i],
brcmf_dbg(SCAN, ">>> Active scan req for ssid (%s)\n", pmk[npmk].pmkid[i + 1], pmk[npmk].pmkid[i + 2],
request->ssids[i].ssid); pmk[npmk].pmkid[i + 3]);
/* err = brcmf_update_pmklist(cfg, ifp);
* match_set ssids is a supert set of n_ssid list,
* so we need not add these set seperately.
*/
}
}
if (request->n_match_sets > 0) { brcmf_dbg(TRACE, "Exit\n");
/* clean up everything */ return err;
ret = brcmf_dev_pno_clean(ndev); }
if (ret < 0) {
brcmf_err("failed error=%d\n", ret);
return ret;
}
/* configure pno */ static s32
if (brcmf_dev_pno_config(ifp, request)) brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev,
return -EINVAL; struct cfg80211_pmksa *pmksa)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pmksa *pmk = &cfg->pmk_list.pmk[0];
s32 err;
u32 npmk, i;
/* configure each match set */ brcmf_dbg(TRACE, "Enter\n");
for (i = 0; i < request->n_match_sets; i++) { if (!check_vif_up(ifp->vif))
struct cfg80211_ssid *ssid; return -EIO;
u32 ssid_len;
ssid = &request->match_sets[i].ssid; brcmf_dbg(CONN, "del_pmksa - PMK bssid = %pM\n", &pmksa->bssid);
ssid_len = ssid->ssid_len;
if (!ssid_len) { npmk = le32_to_cpu(cfg->pmk_list.npmk);
brcmf_err("skip broadcast ssid\n"); for (i = 0; i < npmk; i++)
continue; if (!memcmp(&pmksa->bssid, &pmk[i].bssid, ETH_ALEN))
} break;
pfn.auth = cpu_to_le32(WLAN_AUTH_OPEN);
pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); if ((npmk > 0) && (i < npmk)) {
pfn.wsec = cpu_to_le32(0); for (; i < (npmk - 1); i++) {
pfn.infra = cpu_to_le32(1); memcpy(&pmk[i].bssid, &pmk[i + 1].bssid, ETH_ALEN);
pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); memcpy(&pmk[i].pmkid, &pmk[i + 1].pmkid,
pfn.ssid.SSID_len = cpu_to_le32(ssid_len); WLAN_PMKID_LEN);
memcpy(pfn.ssid.SSID, ssid->ssid, ssid_len);
ret = brcmf_fil_iovar_data_set(ifp, "pfn_add", &pfn,
sizeof(pfn));
brcmf_dbg(SCAN, ">>> PNO filter %s for ssid (%s)\n",
ret == 0 ? "set" : "failed", ssid->ssid);
}
/* Enable the PNO */
if (brcmf_fil_iovar_int_set(ifp, "pfn", 1) < 0) {
brcmf_err("PNO enable failed!! ret=%d\n", ret);
return -EINVAL;
} }
memset(&pmk[i], 0, sizeof(*pmk));
cfg->pmk_list.npmk = cpu_to_le32(npmk - 1);
} else { } else {
brcmf_err("Cache entry not found\n");
return -EINVAL; return -EINVAL;
} }
return 0; err = brcmf_update_pmklist(cfg, ifp);
brcmf_dbg(TRACE, "Exit\n");
return err;
} }
static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy, static s32
struct net_device *ndev) brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
s32 err;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif))
return -EIO;
memset(&cfg->pmk_list, 0, sizeof(cfg->pmk_list));
err = brcmf_update_pmklist(cfg, ifp);
brcmf_dbg(TRACE, "Exit\n");
return err;
brcmf_dbg(SCAN, "enter\n");
brcmf_dev_pno_clean(ndev);
if (cfg->sched_escan)
brcmf_notify_escan_complete(cfg, netdev_priv(ndev), true, true);
return 0;
} }
static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp) static s32 brcmf_configure_opensecurity(struct brcmf_if *ifp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment