|
@@ -445,9 +445,103 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void brcmf_set_mpc(struct net_device *ndev, int mpc)
|
|
|
+{
|
|
|
+ struct brcmf_if *ifp = netdev_priv(ndev);
|
|
|
+ s32 err = 0;
|
|
|
+
|
|
|
+ if (check_vif_up(ifp->vif)) {
|
|
|
+ err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
|
|
|
+ if (err) {
|
|
|
+ brcmf_err("fail to set mpc\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ brcmf_dbg(INFO, "MPC : %d\n", mpc);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static s32
|
|
|
+brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|
|
+ struct net_device *ndev,
|
|
|
+ bool aborted, bool fw_abort)
|
|
|
+{
|
|
|
+ struct brcmf_scan_params_le params_le;
|
|
|
+ struct cfg80211_scan_request *scan_request;
|
|
|
+ s32 err = 0;
|
|
|
+
|
|
|
+ brcmf_dbg(SCAN, "Enter\n");
|
|
|
+
|
|
|
+ /* clear scan request, because the FW abort can cause a second call */
|
|
|
+ /* to this functon and might cause a double cfg80211_scan_done */
|
|
|
+ scan_request = cfg->scan_request;
|
|
|
+ cfg->scan_request = NULL;
|
|
|
+
|
|
|
+ if (timer_pending(&cfg->escan_timeout))
|
|
|
+ del_timer_sync(&cfg->escan_timeout);
|
|
|
+
|
|
|
+ if (fw_abort) {
|
|
|
+ /* Do a scan abort to stop the driver's scan engine */
|
|
|
+ brcmf_dbg(SCAN, "ABORT scan in firmware\n");
|
|
|
+ memset(¶ms_le, 0, sizeof(params_le));
|
|
|
+ memset(params_le.bssid, 0xFF, ETH_ALEN);
|
|
|
+ params_le.bss_type = DOT11_BSSTYPE_ANY;
|
|
|
+ params_le.scan_type = 0;
|
|
|
+ params_le.channel_num = cpu_to_le32(1);
|
|
|
+ params_le.nprobes = cpu_to_le32(1);
|
|
|
+ params_le.active_time = cpu_to_le32(-1);
|
|
|
+ params_le.passive_time = cpu_to_le32(-1);
|
|
|
+ params_le.home_time = cpu_to_le32(-1);
|
|
|
+ /* Scan is aborted by setting channel_list[0] to -1 */
|
|
|
+ params_le.channel_list[0] = cpu_to_le16(-1);
|
|
|
+ /* E-Scan (or anyother type) can be aborted by SCAN */
|
|
|
+ err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
|
|
|
+ ¶ms_le, sizeof(params_le));
|
|
|
+ if (err)
|
|
|
+ brcmf_err("Scan abort failed\n");
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * e-scan can be initiated by scheduled scan
|
|
|
+ * which takes precedence.
|
|
|
+ */
|
|
|
+ if (cfg->sched_escan) {
|
|
|
+ brcmf_dbg(SCAN, "scheduled scan completed\n");
|
|
|
+ cfg->sched_escan = false;
|
|
|
+ if (!aborted)
|
|
|
+ cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
|
|
|
+ brcmf_set_mpc(ndev, 1);
|
|
|
+ } else if (scan_request) {
|
|
|
+ brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
|
|
|
+ aborted ? "Aborted" : "Done");
|
|
|
+ cfg80211_scan_done(scan_request, aborted);
|
|
|
+ brcmf_set_mpc(ndev, 1);
|
|
|
+ }
|
|
|
+ if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
|
|
|
+ brcmf_err("Scan complete while device not scanning\n");
|
|
|
+ return -EPERM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
static
|
|
|
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev)
|
|
|
{
|
|
|
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
|
|
|
+ struct net_device *ndev = wdev->netdev;
|
|
|
+
|
|
|
+ /* vif event pending in firmware */
|
|
|
+ if (brcmf_cfg80211_vif_event_armed(cfg))
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ if (ndev) {
|
|
|
+ if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status) &&
|
|
|
+ cfg->escan_info.ndev == ndev)
|
|
|
+ brcmf_notify_escan_complete(cfg, ndev, true,
|
|
|
+ true);
|
|
|
+
|
|
|
+ brcmf_fil_iovar_int_set(netdev_priv(ndev), "mpc", 1);
|
|
|
+ }
|
|
|
+
|
|
|
switch (wdev->iftype) {
|
|
|
case NL80211_IFTYPE_ADHOC:
|
|
|
case NL80211_IFTYPE_STATION:
|
|
@@ -525,21 +619,6 @@ done:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
-static void brcmf_set_mpc(struct net_device *ndev, int mpc)
|
|
|
-{
|
|
|
- struct brcmf_if *ifp = netdev_priv(ndev);
|
|
|
- s32 err = 0;
|
|
|
-
|
|
|
- if (check_vif_up(ifp->vif)) {
|
|
|
- err = brcmf_fil_iovar_int_set(ifp, "mpc", mpc);
|
|
|
- if (err) {
|
|
|
- brcmf_err("fail to set mpc\n");
|
|
|
- return;
|
|
|
- }
|
|
|
- brcmf_dbg(INFO, "MPC : %d\n", mpc);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
|
|
|
struct cfg80211_scan_request *request)
|
|
|
{
|
|
@@ -619,69 +698,6 @@ static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
|
|
|
(n_channels & BRCMF_SCAN_PARAMS_COUNT_MASK));
|
|
|
}
|
|
|
|
|
|
-static s32
|
|
|
-brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
|
|
|
- struct net_device *ndev,
|
|
|
- bool aborted, bool fw_abort)
|
|
|
-{
|
|
|
- struct brcmf_scan_params_le params_le;
|
|
|
- struct cfg80211_scan_request *scan_request;
|
|
|
- s32 err = 0;
|
|
|
-
|
|
|
- brcmf_dbg(SCAN, "Enter\n");
|
|
|
-
|
|
|
- /* clear scan request, because the FW abort can cause a second call */
|
|
|
- /* to this functon and might cause a double cfg80211_scan_done */
|
|
|
- scan_request = cfg->scan_request;
|
|
|
- cfg->scan_request = NULL;
|
|
|
-
|
|
|
- if (timer_pending(&cfg->escan_timeout))
|
|
|
- del_timer_sync(&cfg->escan_timeout);
|
|
|
-
|
|
|
- if (fw_abort) {
|
|
|
- /* Do a scan abort to stop the driver's scan engine */
|
|
|
- brcmf_dbg(SCAN, "ABORT scan in firmware\n");
|
|
|
- memset(¶ms_le, 0, sizeof(params_le));
|
|
|
- memset(params_le.bssid, 0xFF, ETH_ALEN);
|
|
|
- params_le.bss_type = DOT11_BSSTYPE_ANY;
|
|
|
- params_le.scan_type = 0;
|
|
|
- params_le.channel_num = cpu_to_le32(1);
|
|
|
- params_le.nprobes = cpu_to_le32(1);
|
|
|
- params_le.active_time = cpu_to_le32(-1);
|
|
|
- params_le.passive_time = cpu_to_le32(-1);
|
|
|
- params_le.home_time = cpu_to_le32(-1);
|
|
|
- /* Scan is aborted by setting channel_list[0] to -1 */
|
|
|
- params_le.channel_list[0] = cpu_to_le16(-1);
|
|
|
- /* E-Scan (or anyother type) can be aborted by SCAN */
|
|
|
- err = brcmf_fil_cmd_data_set(netdev_priv(ndev), BRCMF_C_SCAN,
|
|
|
- ¶ms_le, sizeof(params_le));
|
|
|
- if (err)
|
|
|
- brcmf_err("Scan abort failed\n");
|
|
|
- }
|
|
|
- /*
|
|
|
- * e-scan can be initiated by scheduled scan
|
|
|
- * which takes precedence.
|
|
|
- */
|
|
|
- if (cfg->sched_escan) {
|
|
|
- brcmf_dbg(SCAN, "scheduled scan completed\n");
|
|
|
- cfg->sched_escan = false;
|
|
|
- if (!aborted)
|
|
|
- cfg80211_sched_scan_results(cfg_to_wiphy(cfg));
|
|
|
- brcmf_set_mpc(ndev, 1);
|
|
|
- } else if (scan_request) {
|
|
|
- brcmf_dbg(SCAN, "ESCAN Completed scan: %s\n",
|
|
|
- aborted ? "Aborted" : "Done");
|
|
|
- cfg80211_scan_done(scan_request, aborted);
|
|
|
- brcmf_set_mpc(ndev, 1);
|
|
|
- }
|
|
|
- if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
|
|
|
- brcmf_err("Scan complete while device not scanning\n");
|
|
|
- return -EPERM;
|
|
|
- }
|
|
|
-
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static s32
|
|
|
brcmf_run_escan(struct brcmf_cfg80211_info *cfg, struct net_device *ndev,
|
|
|
struct cfg80211_scan_request *request, u16 action)
|
|
@@ -3474,6 +3490,22 @@ exit:
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+s32 brcmf_vif_clear_mgmt_ies(struct brcmf_cfg80211_vif *vif)
|
|
|
+{
|
|
|
+ s32 pktflags[] = {
|
|
|
+ BRCMF_VNDR_IE_PRBREQ_FLAG,
|
|
|
+ BRCMF_VNDR_IE_PRBRSP_FLAG,
|
|
|
+ BRCMF_VNDR_IE_BEACON_FLAG
|
|
|
+ };
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < ARRAY_SIZE(pktflags); i++)
|
|
|
+ brcmf_vif_set_mgmt_ie(vif, pktflags[i], NULL, 0);
|
|
|
+
|
|
|
+ memset(&vif->saved_ie, 0, sizeof(vif->saved_ie));
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static s32
|
|
|
brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
|
|
|
struct cfg80211_ap_settings *settings)
|
|
@@ -4260,6 +4292,12 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
|
|
|
struct station_info sinfo;
|
|
|
|
|
|
brcmf_dbg(CONN, "event %d, reason %d\n", event, reason);
|
|
|
+ if (event == BRCMF_E_LINK && reason == BRCMF_E_REASON_LINK_BSSCFG_DIS &&
|
|
|
+ ndev != cfg_to_ndev(cfg)) {
|
|
|
+ brcmf_dbg(CONN, "AP mode link down\n");
|
|
|
+ complete(&cfg->vif_disabled);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
|
|
|
(reason == BRCMF_E_STATUS_SUCCESS)) {
|
|
@@ -4316,6 +4354,8 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
|
|
|
}
|
|
|
brcmf_link_down(ifp->vif);
|
|
|
brcmf_init_prof(ndev_to_prof(ndev));
|
|
|
+ if (ndev != cfg_to_ndev(cfg))
|
|
|
+ complete(&cfg->vif_disabled);
|
|
|
} else if (brcmf_is_nonetwork(cfg, e)) {
|
|
|
if (brcmf_is_ibssmode(ifp->vif))
|
|
|
clear_bit(BRCMF_VIF_STATUS_CONNECTING,
|
|
@@ -4401,7 +4441,6 @@ static s32 brcmf_notify_vif_event(struct brcmf_if *ifp,
|
|
|
|
|
|
case BRCMF_E_IF_DEL:
|
|
|
ifp->vif = NULL;
|
|
|
- brcmf_free_vif(vif);
|
|
|
mutex_unlock(&event->vif_event_lock);
|
|
|
/* event may not be upon user request */
|
|
|
if (brcmf_cfg80211_vif_event_armed(cfg))
|
|
@@ -4507,7 +4546,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
|
|
|
mutex_init(&cfg->usr_sync);
|
|
|
brcmf_init_escan(cfg);
|
|
|
brcmf_init_conf(cfg->conf);
|
|
|
-
|
|
|
+ init_completion(&cfg->vif_disabled);
|
|
|
return err;
|
|
|
}
|
|
|
|