/* * Copyright (c) 2022, Fuzhou Rockchip Electronics Co., Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include "rk960.h" #include "scan.h" #include "sta.h" #include "pm.h" #include "debug.h" #include <../net/mac80211/ieee80211_i.h> #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) #define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR #endif static void rk960_scan_restart_delayed(struct rk960_vif *priv); #ifdef CONFIG_RK960_TESTMODE static int rk960_advance_scan_start(struct rk960_common *hw_priv) { int tmo = 0; tmo += hw_priv->advanceScanElems.duration; rk960_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000); /* Invoke Advance Scan Duration Timeout Handler */ queue_delayed_work(hw_priv->workqueue, &hw_priv->advance_scan_timeout, tmo * HZ / 1000); return 0; } #endif static void rk960_remove_wps_p2p_ie(struct wsm_template_frame *frame) { u8 *ies; u32 ies_len; u32 ie_len; u32 p2p_ie_len = 0; u32 wps_ie_len = 0; ies = &frame->skb->data[sizeof(struct ieee80211_hdr_3addr)]; ies_len = frame->skb->len - sizeof(struct ieee80211_hdr_3addr); while (ies_len >= 6) { ie_len = ies[1] + 2; if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && (ies[2] == 0x00 && ies[3] == 0x50 && ies[4] == 0xf2 && ies[5] == 0x04)) { wps_ie_len = ie_len; memmove(ies, ies + ie_len, ies_len); ies_len -= ie_len; } else if ((ies[0] == WLAN_EID_VENDOR_SPECIFIC) && (ies[2] == 0x50 && ies[3] == 0x6f && ies[4] == 0x9a && ies[5] == 0x09)) { p2p_ie_len = ie_len; memmove(ies, ies + ie_len, ies_len); ies_len -= ie_len; } else { ies += ie_len; ies_len -= ie_len; } } if (p2p_ie_len || wps_ie_len) { skb_trim(frame->skb, frame->skb->len - (p2p_ie_len + wps_ie_len)); } } #ifdef CONFIG_RK960_TESTMODE static int rk960_disable_filtering(struct rk960_vif *priv) { int ret = 0; bool bssid_filtering = 0; struct wsm_rx_filter rx_filter; struct wsm_beacon_filter_control bf_control; struct rk960_common *hw_priv = rk960_vifpriv_to_hwpriv(priv); /* RX Filter Disable */ rx_filter.promiscuous = 0; rx_filter.bssid = 0; rx_filter.fcs = 0; ret = wsm_set_rx_filter(hw_priv, &rx_filter, priv->if_id); /* Beacon Filter Disable */ bf_control.enabled = 0; bf_control.bcn_count = 1; if (!ret) ret = wsm_beacon_filter_control(hw_priv, &bf_control, priv->if_id); /* BSSID Filter Disable */ if (!ret) ret = wsm_set_bssid_filtering(hw_priv, bssid_filtering, priv->if_id); return ret; } #endif static int rk960_scan_start(struct rk960_vif *priv, struct wsm_scan *scan) { int ret, i; #ifdef FPGA_SETUP int tmo = 5000; #else int tmo = 5000; #endif struct rk960_common *hw_priv = rk960_vifpriv_to_hwpriv(priv); for (i = 0; i < scan->numOfChannels; ++i) tmo += scan->ch[i].maxChannelTime + 10; #ifdef RK960_CSYNC_ADJUST rk960_csync_scan(hw_priv); #endif atomic_set(&hw_priv->scan.in_progress, 1); atomic_set(&hw_priv->recent_scan, 1); rk960_pm_stay_awake(&hw_priv->pm_state, tmo * HZ / 1000); queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, tmo * HZ / 1000); #ifdef P2P_MULTIVIF ret = wsm_scan(hw_priv, scan, priv->if_id ? 1 : 0); #else ret = wsm_scan(hw_priv, scan, priv->if_id); #endif if (unlikely(ret)) { #ifdef RK960_CSYNC_ADJUST rk960_csync_scan_complete(hw_priv); #endif atomic_set(&hw_priv->scan.in_progress, 0); cancel_delayed_work_sync(&hw_priv->scan.timeout); rk960_scan_restart_delayed(priv); } return ret; } #ifdef ROAM_OFFLOAD static int rk960_sched_scan_start(struct rk960_vif *priv, struct wsm_scan *scan) { int ret; struct rk960_common *hw_priv = rk960_vifpriv_to_hwpriv(priv); ret = wsm_scan(hw_priv, scan, priv->if_id); if (unlikely(ret)) { #ifdef RK960_CSYNC_ADJUST rk960_csync_scan_complete(hw_priv); #endif atomic_set(&hw_priv->scan.in_progress, 0); } return ret; } #endif /*ROAM_OFFLOAD */ int rk960_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) struct ieee80211_scan_request *hw_req) #else struct cfg80211_scan_request *req) #endif { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) struct cfg80211_scan_request *req = &hw_req->req; #endif struct rk960_common *hw_priv = hw->priv; struct rk960_vif *priv = rk960_get_vif_from_ieee80211(vif); struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, }; int i; int ret = 0; #ifdef CONFIG_RK960_TESTMODE u16 advance_scan_req_channel; #endif /* Scan when P2P_GO corrupt firmware MiniAP mode */ if (priv->join_status == RK960_JOIN_STATUS_AP) return -EOPNOTSUPP; #ifdef ROAM_OFFLOAD if (hw_priv->scan.sched_req) { RK960_DEBUG_SCAN("%s: sched_scan inprocess\n", __func__); return -EBUSY; } #endif RK960_DEBUG_SCAN("[SCAN] Scan request for %d chs %d SSIDs no_cck %d.\n", req->n_channels, req->n_ssids, req->no_cck); #ifdef SUPPORT_FWCR if (priv->join_status < RK960_JOIN_STATUS_STA) rk960_fwcr_deinit(hw_priv); if (!rk960_fwcr_recovery_scan(hw_priv, priv)) return 0; #endif if (work_pending(&priv->offchannel_work) || (hw_priv->roc_if_id != -1) || (!req->no_cck && delayed_work_pending(&priv->join_timeout))) { RK960_INFO_SCAN("[SCAN] Offchannel work pending, " "ignoring scan work %d\n", hw_priv->roc_if_id); return -EBUSY; } if (req->n_ssids == 1 && !req->ssids[0].ssid_len) req->n_ssids = 0; if (req->n_ssids > hw->wiphy->max_scan_ssids) return -EINVAL; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, req->ie_len); #else frame.skb = ieee80211_probereq_get(hw, vif, NULL, 0, req->ie_len); #endif if (req->ie_len) memcpy(skb_put(frame.skb, req->ie_len), req->ie, req->ie_len); #else frame.skb = ieee80211_probereq_get(hw, vif, NULL, 0, req->ie, req->ie_len); #endif if (!frame.skb) return -ENOMEM; hw_priv->scan.in_txrx_burst = rk960_is_txrx_burst(hw_priv); /* will be unlocked in rk960_scan_work() */ down(&hw_priv->scan.lock); mutex_lock(&hw_priv->conf_mutex); #ifdef CONFIG_RK960_TESTMODE /* Active Scan - Serving Channel Request Handling */ advance_scan_req_channel = req->channels[0]->hw_value; if (hw_priv->enable_advance_scan && (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_ACTIVE) && (priv->join_status == RK960_JOIN_STATUS_STA) && (hw_priv->channel->hw_value == advance_scan_req_channel)) { BUG_ON(hw_priv->scan.req); /* wsm_lock_tx(hw_priv); */ wsm_vif_lock_tx(priv); hw_priv->scan.if_id = priv->if_id; /* Disable Power Save */ if (priv->powersave_mode.pmMode & WSM_PSM_PS) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_ACTIVE; wsm_set_pm(hw_priv, &pm, priv->if_id); } /* Disable Rx Beacon and Bssid filter */ ret = rk960_disable_filtering(priv); if (ret) RK960_ERROR_SCAN ("%s: Disable BSSID or Beacon filtering failed: %d.\n", __func__, ret); wsm_unlock_tx(hw_priv); mutex_unlock(&hw_priv->conf_mutex); /* Transmit Probe Request with Broadcast SSID */ rk960_tx(hw, frame.skb); /* Start Advance Scan Timer */ rk960_advance_scan_start(hw_priv); } else { #endif if (frame.skb) { if (priv->if_id == 0) rk960_remove_wps_p2p_ie(&frame); #ifdef P2P_MULTIVIF ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id ? 1 : 0); #else ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); #endif if (ret) { mutex_unlock(&hw_priv->conf_mutex); up(&hw_priv->scan.lock); dev_kfree_skb(frame.skb); return ret; } } wsm_vif_lock_tx(priv); BUG_ON(hw_priv->scan.req); hw_priv->scan.req = req; hw_priv->scan.n_ssids = 0; hw_priv->scan.status = 0; hw_priv->scan.begin = &req->channels[0]; hw_priv->scan.curr = hw_priv->scan.begin; hw_priv->scan.end = &req->channels[req->n_channels]; hw_priv->scan.output_power = hw_priv->output_power; hw_priv->scan.if_id = priv->if_id; hw_priv->scan.p2p_probe = req->no_cck; /* TODO:COMBO: Populate BIT4 in scanflags to decide on which MAC * address the SCAN request will be sent */ for (i = 0; i < req->n_ssids; ++i) { struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; BUG_ON(req->ssids[i].ssid_len > sizeof(dst->ssid)); memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); dst->length = req->ssids[i].ssid_len; ++hw_priv->scan.n_ssids; RK960_DEBUG_SCAN("ssid%d %s\n", i, req->ssids[i].ssid); } mutex_unlock(&hw_priv->conf_mutex); hw_priv->scan_counter++; RK960_DEBUG_SCAN("scan_start: %d\n", hw_priv->scan_counter); if (frame.skb) dev_kfree_skb(frame.skb); queue_work(hw_priv->workqueue, &hw_priv->scan.work); #ifdef CONFIG_RK960_TESTMODE } #endif return 0; } #ifdef ROAM_OFFLOAD int rk960_hw_sched_scan_start(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_sched_scan_request *req, #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) struct ieee80211_scan_ies *ies) #else struct ieee80211_sched_scan_ies *ies) #endif { struct rk960_common *hw_priv = hw->priv; struct rk960_vif *priv = rk960_get_vif_from_ieee80211(vif); struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, }; int i; if (hw_priv->wowlan_disable) { RK960_DEBUG_SCAN("%s: EOPNOTSUPP\n", __func__); return -EOPNOTSUPP; } if (hw_priv->scan.req) { RK960_DEBUG_SCAN("%s: scan inprocess\n", __func__); return -EBUSY; } RK960_INFO_SCAN("[SCAN] Scheduled scan request-->.\n"); if (!priv->vif) return -EINVAL; /* Scan when P2P_GO corrupt firmware MiniAP mode */ if (priv->join_status == RK960_JOIN_STATUS_AP) return -EOPNOTSUPP; RK960_DEBUG_SCAN ("[SCAN] Scheduled scan: n_ssids %d, ssid[0].len = %d\n", req->n_ssids, req->ssids[0].ssid_len); RK960_DEBUG_SCAN(" n_channels = %d\n", req->n_channels); #if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0)) RK960_DEBUG_SCAN(" interval = %d\n", req->interval); #endif RK960_DEBUG_SCAN(" ie_len = %d\n", req->ie_len); RK960_DEBUG_SCAN(" flags = %x\n", req->flags); RK960_DEBUG_SCAN(" n_match_sets = %x\n", req->n_match_sets); for (i = 0; i < req->n_match_sets; i++) { if (req->n_match_sets) RK960_DEBUG_SCAN(" ssid %s rssi_thold = %d\n", req->match_sets[i].ssid, req->match_sets[i].rssi_thold); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) RK960_DEBUG_SCAN(" interval = %x\n", req->scan_plans[0].interval); RK960_DEBUG_SCAN(" relative_rssi_set = %x\n", req->relative_rssi_set); RK960_DEBUG_SCAN(" relative_rssi = %x\n", req->relative_rssi); RK960_DEBUG_SCAN(" rssi_adjust = %x\n", req->rssi_adjust); #else RK960_DEBUG_SCAN(" min_rssi_thold = %x\n", req->min_rssi_thold); #endif if (req->n_ssids == 1 && !req->ssids[0].ssid_len) req->n_ssids = 0; RK960_DEBUG_SCAN("[SCAN] Scan request for %d SSIDs.\n", req->n_ssids); if (req->n_ssids > hw->wiphy->max_scan_ssids) return -EINVAL; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) frame.skb = ieee80211_probereq_get(hw, priv->vif->addr, NULL, 0, ies->len[0] + ies->common_ie_len); if (ies->len[0]) memcpy(skb_put(frame.skb, ies->len[0]), ies->ies[0], ies->len[0]); if (ies->common_ie_len) memcpy(skb_put(frame.skb, ies->common_ie_len), ies->common_ies, ies->common_ie_len); #else frame.skb = ieee80211_probereq_get(hw, vif, NULL, 0, ies->len[0]); if (ies->len[0]) memcpy(skb_put(frame.skb, ies->len[0]), ies->ie[0], ies->len[0]); #endif #else frame.skb = ieee80211_probereq_get(hw, priv->vif, NULL, 0, ies->ie[0], ies->len[0]); #endif if (!frame.skb) return -ENOMEM; if (req->channels[0]->band == IEEE80211_BAND_2GHZ) hw_priv->num_scanchannels = 0; else hw_priv->num_scanchannels = hw_priv->num_2g_channels; for (i = 0; i < req->n_channels; i++) { hw_priv->scan_channels[hw_priv->num_scanchannels + i].number = req->channels[i]->hw_value; if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN) { hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 50; hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 110; } else { hw_priv->scan_channels[hw_priv->num_scanchannels + i].minChannelTime = 10; hw_priv->scan_channels[hw_priv->num_scanchannels + i].maxChannelTime = 40; } hw_priv->scan_channels[hw_priv->num_scanchannels + i].txPowerLevel = req->channels[i]->max_power; } if (req->channels[0]->band == IEEE80211_BAND_2GHZ) hw_priv->num_2g_channels = req->n_channels; else hw_priv->num_5g_channels = req->n_channels; hw_priv->num_scanchannels = hw_priv->num_2g_channels + hw_priv->num_5g_channels; /* will be unlocked in rk960_scan_work() */ down(&hw_priv->scan.lock); mutex_lock(&hw_priv->conf_mutex); if (frame.skb) { int ret; if (priv->if_id == 0) rk960_remove_wps_p2p_ie(&frame); ret = wsm_set_template_frame(hw_priv, &frame, priv->if_id); if (0 == ret) { /* Host want to be the probe responder. */ ret = wsm_set_probe_responder(priv, true); } if (ret) { mutex_unlock(&hw_priv->conf_mutex); up(&hw_priv->scan.lock); dev_kfree_skb(frame.skb); return ret; } } wsm_lock_tx(hw_priv); BUG_ON(hw_priv->scan.req); hw_priv->scan.sched_req = req; hw_priv->scan.n_ssids = 0; hw_priv->scan.status = 0; hw_priv->scan.begin = &req->channels[0]; hw_priv->scan.curr = hw_priv->scan.begin; hw_priv->scan.end = &req->channels[req->n_channels]; hw_priv->scan.output_power = hw_priv->output_power; for (i = 0; i < req->n_ssids; ++i) { struct wsm_ssid *dst = &hw_priv->scan.ssids[hw_priv->scan.n_ssids]; if (req->ssids[i].ssid_len > sizeof(dst->ssid)) req->ssids[i].ssid_len = sizeof(dst->ssid); memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); dst->length = req->ssids[i].ssid_len; ++hw_priv->scan.n_ssids; { u8 j; RK960_DEBUG_SCAN("[SCAN] SSID %d\n", i); for (j = 0; j < req->ssids[i].ssid_len; j++) RK960_DEBUG_SCAN("[SCAN] 0x%x\n", req->ssids[i].ssid[j]); } } mutex_unlock(&hw_priv->conf_mutex); if (frame.skb) dev_kfree_skb(frame.skb); queue_work(hw_priv->workqueue, &hw_priv->scan.swork); RK960_DEBUG_SCAN("<--[SCAN] Scheduled scan request.\n"); return 0; } #endif /*ROAM_OFFLOAD */ #define SCAN_TIME_ADJUST void rk960_scan_work(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, scan.work); struct rk960_vif *priv, *vif; struct ieee80211_channel **it; struct wsm_scan scan = { .scanType = WSM_SCAN_TYPE_FOREGROUND, .scanFlags = 0, /* TODO:COMBO */ //.scanFlags = WSM_SCAN_FLAG_SPLIT_METHOD, /* TODO:COMBO */ }; bool first_run; int i; const u32 ProbeRequestTime = 2; const u32 ChannelRemainTime = 15; u32 maxChannelTime; #ifdef CONFIG_RK960_TESTMODE int ret = 0; u16 advance_scan_req_channel = hw_priv->scan.begin[0]->hw_value; #endif #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) struct cfg80211_scan_info info = { .aborted = false, }; #endif priv = __rk960_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); /*TODO: COMBO: introduce locking so vif is not removed in meanwhile */ if (!priv) { RK960_INFO_SCAN("[SCAN] interface removed, " "ignoring scan work\n"); return; } if (priv->if_id) scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; else scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; //rk960_for_each_vif(hw_priv, vif, i) { for (i = 0; i < RK960_MAX_VIFS; i++) { vif = hw_priv->vif_list[i] ? rk960_get_vif_from_ieee80211(hw_priv->vif_list[i]) : NULL; if (!vif) continue; if (vif->bss_loss_status > RK960_BSS_LOSS_NONE) scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; } first_run = hw_priv->scan.begin == hw_priv->scan.curr && hw_priv->scan.begin != hw_priv->scan.end; if (first_run) { /* Firmware gets crazy if scan request is sent * when STA is joined but not yet associated. * Force unjoin in this case. */ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) rk960_join_timeout(&priv->join_timeout.work); } mutex_lock(&hw_priv->conf_mutex); if (first_run) { #ifdef CONFIG_RK960_TESTMODE /* Passive Scan - Serving Channel Request Handling */ if (hw_priv->enable_advance_scan && (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) && (priv->join_status == RK960_JOIN_STATUS_STA) && (hw_priv->channel->hw_value == advance_scan_req_channel)) { /* If Advance Scan Request is for Serving Channel Device * should be Active and Filtering Should be Disable */ if (priv->powersave_mode.pmMode & WSM_PSM_PS) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_ACTIVE; wsm_set_pm(hw_priv, &pm, priv->if_id); } /* Disable Rx Beacon and Bssid filter */ ret = rk960_disable_filtering(priv); if (ret) RK960_ERROR_SCAN ("%s: Disable BSSID or Beacon filtering failed: %d.\n", __func__, ret); } else if (hw_priv->enable_advance_scan && (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) && (priv->join_status == RK960_JOIN_STATUS_STA)) { if (priv->join_status == RK960_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_PS; rk960_set_pm(priv, &pm); } } else { #endif #if 0 if (priv->join_status == RK960_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) { struct wsm_set_pm pm = priv->powersave_mode; pm.pmMode = WSM_PSM_PS; rk960_set_pm(priv, &pm); } else #endif if (priv->join_status == RK960_JOIN_STATUS_MONITOR) { /* FW bug: driver has to restart p2p-dev mode * after scan */ rk960_disable_listening(priv); } #ifdef CONFIG_RK960_TESTMODE } #endif } if (!hw_priv->scan.req || (hw_priv->scan.curr == hw_priv->scan.end)) { #ifdef CONFIG_RK960_TESTMODE if (hw_priv->enable_advance_scan && (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) && (priv->join_status == RK960_JOIN_STATUS_STA) && (hw_priv->channel->hw_value == advance_scan_req_channel)) { /* WSM Lock should be held here for WSM APIs */ wsm_vif_lock_tx(priv); /* wsm_lock_tx(priv); */ /* Once Duration is Over, enable filtering * and Revert Back Power Save */ if (priv->powersave_mode.pmMode & WSM_PSM_PS) wsm_set_pm(hw_priv, &priv->powersave_mode, priv->if_id); rk960_update_filtering(priv); } else { if (!hw_priv->enable_advance_scan) { #endif if (hw_priv->scan.output_power != hw_priv->output_power) /* TODO:COMBO: Change when mac80211 implementation * is available for output power also */ #ifdef P2P_MULTIVIF WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, priv->if_id ? 1 : 0)); #else WARN_ON(wsm_set_output_power(hw_priv, hw_priv->output_power * 10, priv->if_id)); #endif #ifdef CONFIG_RK960_TESTMODE } } #endif #if 0 if (priv->join_status == RK960_JOIN_STATUS_STA && !(priv->powersave_mode.pmMode & WSM_PSM_PS)) rk960_set_pm(priv, &priv->powersave_mode); #endif if (hw_priv->scan.status < 0) RK960_ERROR_SCAN("[SCAN] Scan failed (%d).\n", hw_priv->scan.status); else if (hw_priv->scan.req) RK960_DEBUG_SCAN("[SCAN] Scan completed.\n"); else RK960_INFO_SCAN("[SCAN] Scan canceled.\n"); hw_priv->scan.in_txrx_burst = false; hw_priv->scan.req = NULL; rk960_scan_restart_delayed(priv); #ifdef CONFIG_RK960_TESTMODE hw_priv->enable_advance_scan = false; #endif /* CONFIG_RK960_TESTMODE */ wsm_unlock_tx(hw_priv); mutex_unlock(&hw_priv->conf_mutex); hw_priv->scan_comp_counter++; RK960_DEBUG_SCAN("scan_completed: %d(%d)\n", hw_priv->scan_comp_counter, hw_priv->scan.status); #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) if (hw_priv->scan.status) info.aborted = true; ieee80211_scan_completed(hw_priv->hw, &info); #else ieee80211_scan_completed(hw_priv->hw, hw_priv->scan.status ? 1 : 0); #endif up(&hw_priv->scan.lock); return; } else { struct ieee80211_channel *first = *hw_priv->scan.curr; for (it = hw_priv->scan.curr + 1, i = 1; it != hw_priv->scan.end && i < WSM_SCAN_MAX_NUM_OF_CHANNELS; ++it, ++i) { if ((*it)->band != first->band) break; if (((*it)->flags ^ first->flags) & IEEE80211_CHAN_PASSIVE_SCAN) break; if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && (*it)->max_power != first->max_power) break; } scan.band = first->band; if (hw_priv->scan.req->no_cck) scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; else scan.maxTransmitRate = WSM_TRANSMIT_RATE_1; #ifdef CONFIG_RK960_TESTMODE if (hw_priv->enable_advance_scan) { if (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) scan.numOfProbeRequests = 0; else scan.numOfProbeRequests = 1; } else { #endif /* TODO: Is it optimal? */ scan.numOfProbeRequests = (first-> flags & IEEE80211_CHAN_PASSIVE_SCAN) ? 0 : 3; #ifdef CONFIG_RK960_TESTMODE } #endif /* CONFIG_RK960_TESTMODE */ scan.numOfSSIDs = hw_priv->scan.n_ssids; scan.ssids = &hw_priv->scan.ssids[0]; scan.numOfChannels = it - hw_priv->scan.curr; /* TODO: Is it optimal? */ #if 0 //def SCAN_TIME_ADJUST scan.probeDelay = 10; if (hw_priv->scan.req->no_cck) { scan.numOfProbeRequests = 3; scan.probeDelay = 15; } #else scan.probeDelay = 100; #endif /* It is not stated in WSM specification, however * FW team says that driver may not use FG scan * when joined. */ if (priv->join_status == RK960_JOIN_STATUS_STA) { scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; } scan.ch = kzalloc(sizeof(struct wsm_scan_ch) * (it - hw_priv->scan.curr), GFP_KERNEL); if (!scan.ch) { hw_priv->scan.status = -ENOMEM; goto fail; } maxChannelTime = (scan.numOfSSIDs * scan.numOfProbeRequests * ProbeRequestTime) + ChannelRemainTime; maxChannelTime = (maxChannelTime < 35) ? 35 : maxChannelTime; for (i = 0; i < scan.numOfChannels; ++i) { scan.ch[i].number = hw_priv->scan.curr[i]->hw_value; #ifdef CONFIG_RK960_TESTMODE if (hw_priv->enable_advance_scan) { scan.ch[i].minChannelTime = hw_priv->advanceScanElems.duration; scan.ch[i].maxChannelTime = hw_priv->advanceScanElems.duration; } else { #endif #ifdef SCAN_TIME_ADJUST if (hw_priv->scan.req->no_cck) { /* decrease channel time in p2p search to solve go-neg action hard to receive issue which cause user confirm UI eject slowly */ #if 1 scan.ch[i].minChannelTime = 5; scan.ch[i].maxChannelTime = 10; #else scan.ch[i].minChannelTime = 35; scan.ch[i].maxChannelTime = maxChannelTime; #endif } else if (hw_priv->scan.in_txrx_burst) { scan.ch[i].minChannelTime = 10; scan.ch[i].maxChannelTime = 15; } else if (rk960_is_apsta_cowork(hw_priv)) { scan.ch[i].minChannelTime = 10; scan.ch[i].maxChannelTime = 32; } else { scan.ch[i].minChannelTime = 50; if (hw_priv->last_channel == scan.ch[i].number) scan.ch[i].maxChannelTime = 210; else scan.ch[i].maxChannelTime = 110; } #else if (hw_priv->scan.curr[i]-> flags & IEEE80211_CHAN_PASSIVE_SCAN) { scan.ch[i].minChannelTime = 50; scan.ch[i].maxChannelTime = 110; } else { scan.ch[i].minChannelTime = 15; scan.ch[i].maxChannelTime = maxChannelTime; } #endif #ifdef CONFIG_RK960_TESTMODE } #endif } #if 0 #ifdef CONFIG_RK960_TESTMODE if (!hw_priv->enable_advance_scan) { #endif if (!(first->flags & IEEE80211_CHAN_PASSIVE_SCAN) && hw_priv->scan.output_power != first->max_power) { hw_priv->scan.output_power = first->max_power; /* TODO:COMBO: Change after mac80211 implementation * complete */ #ifdef P2P_MULTIVIF WARN_ON(wsm_set_output_power(hw_priv, hw_priv->scan.output_power * 10, priv->if_id ? 1 : 0)); #else WARN_ON(wsm_set_output_power(hw_priv, hw_priv->scan.output_power * 10, priv->if_id)); #endif } #ifdef CONFIG_RK960_TESTMODE } #endif #endif #ifdef CONFIG_RK960_TESTMODE if (hw_priv->enable_advance_scan && (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) && (priv->join_status == RK960_JOIN_STATUS_STA) && (hw_priv->channel->hw_value == advance_scan_req_channel)) { /* Start Advance Scan Timer */ hw_priv->scan.status = rk960_advance_scan_start(hw_priv); wsm_unlock_tx(hw_priv); } else #endif hw_priv->scan.status = rk960_scan_start(priv, &scan); kfree(scan.ch); if (WARN_ON(hw_priv->scan.status)) goto fail; hw_priv->scan.curr = it; } mutex_unlock(&hw_priv->conf_mutex); return; fail: hw_priv->scan.curr = hw_priv->scan.end; mutex_unlock(&hw_priv->conf_mutex); queue_work(hw_priv->workqueue, &hw_priv->scan.work); return; } #ifdef ROAM_OFFLOAD void rk960_sched_scan_work(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, scan.swork); struct wsm_scan scan; struct cfg80211_sched_scan_request *req; struct wsm_ssid scan_ssid[WSM_SCAN_MAX_MATCH_SETS_NUM_OF_SSIDS]; int i; struct rk960_vif *priv = rk960_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); if (unlikely(!priv)) { WARN_ON(1); return; } rk960_priv_vif_list_read_unlock(&priv->vif_lock); /* Firmware gets crazy if scan request is sent * when STA is joined but not yet associated. * Force unjoin in this case. */ if (cancel_delayed_work_sync(&priv->join_timeout) > 0) { rk960_join_timeout(&priv->join_timeout.work); } mutex_lock(&hw_priv->conf_mutex); hw_priv->auto_scanning = 1; scan.band = 0; if (priv->join_status == RK960_JOIN_STATUS_STA) scan.scanType = 3; /* auto background */ else scan.scanType = 2; /* auto foreground */ scan.scanFlags = 0x01; /* bit 0 set => forced background scan */ scan.maxTransmitRate = WSM_TRANSMIT_RATE_6; scan.autoScanInterval = (0xba << 24) | (1 * 1024); /* 1 seconds, -70 rssi */ scan.numOfProbeRequests = 1; //scan.numOfChannels = 11; scan.numOfChannels = hw_priv->num_scanchannels; scan.probeDelay = 100; if (!hw_priv->scan.sched_req) { scan.numOfSSIDs = 1; scan_ssid[0].length = priv->ssid_length; memcpy(scan_ssid[0].ssid, priv->ssid, priv->ssid_length); scan.ssids = &scan_ssid[0]; } else { req = hw_priv->scan.sched_req; scan.numOfSSIDs = req->n_match_sets; memset(&scan_ssid, 0, sizeof(scan_ssid)); for (i = 0; i < req->n_match_sets; i++) { if (req->match_sets[i].ssid.ssid_len > 32) { req->match_sets[i].ssid.ssid_len = 32; } memcpy(scan_ssid[i].ssid, req->match_sets[i].ssid.ssid, req->match_sets[i].ssid.ssid_len); scan_ssid[i].length = req->match_sets[i].ssid.ssid_len; } scan.ssids = &scan_ssid[0]; } scan.ch = kzalloc(sizeof(struct wsm_scan_ch) * scan.numOfChannels, GFP_KERNEL); if (!scan.ch) { hw_priv->scan.status = -ENOMEM; goto fail; } for (i = 0; i < scan.numOfChannels; i++) { scan.ch[i].number = hw_priv->scan_channels[i].number; scan.ch[i].minChannelTime = hw_priv->scan_channels[i].minChannelTime; scan.ch[i].maxChannelTime = hw_priv->scan_channels[i].maxChannelTime; scan.ch[i].txPowerLevel = hw_priv->scan_channels[i].txPowerLevel; } #if 0 for (i = 1; i <= scan.numOfChannels; i++) { scan.ch[i - 1].number = i; scan.ch[i - 1].minChannelTime = 10; scan.ch[i - 1].maxChannelTime = 40; } #endif hw_priv->scan.status = rk960_sched_scan_start(priv, &scan); kfree(scan.ch); if (hw_priv->scan.status) goto fail; mutex_unlock(&hw_priv->conf_mutex); return; fail: RK960_ERROR_SCAN("%s: fail %d\n", __func__, hw_priv->scan.status); mutex_unlock(&hw_priv->conf_mutex); queue_work(hw_priv->workqueue, &hw_priv->scan.swork); return; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) int #else void #endif rk960_hw_sched_scan_stop(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rk960_common *hw_priv = hw->priv; mutex_lock(&hw_priv->conf_mutex); if (!hw_priv->auto_scanning) { mutex_unlock(&hw_priv->conf_mutex); return 0; } RK960_INFO_SCAN("[SCAN] Scheduled scan stop-->.\n"); _rk960_hw_sched_scan_stop(hw_priv); hw_priv->scan.sched_req = NULL; if (hw_priv->auto_scanning) { hw_priv->auto_scanning = 0; ieee80211_sched_scan_results(hw_priv->hw); } up(&hw_priv->scan.lock); wsm_unlock_tx(hw_priv); mutex_unlock(&hw_priv->conf_mutex); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) return 0; #endif } void _rk960_hw_sched_scan_stop(struct rk960_common *hw_priv) { struct rk960_vif *priv = rk960_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); if (unlikely(!priv)) return; rk960_priv_vif_list_read_unlock(&priv->vif_lock); wsm_stop_scan(hw_priv, priv->if_id); return; } void rk960_sched_scan_stop_work(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, scan.sched_scan_stop_work. work); rk960_hw_sched_scan_stop(hw_priv->hw, NULL); } #else void rk960_sched_scan_stop_work(struct work_struct *work) { } #endif /*ROAM_OFFLOAD */ static void rk960_scan_restart_delayed(struct rk960_vif *priv) { struct rk960_common *hw_priv = rk960_vifpriv_to_hwpriv(priv); if (priv->delayed_link_loss) { int tmo = priv->cqm_beacon_loss_count; if (hw_priv->scan.direct_probe) tmo = 0; priv->delayed_link_loss = 0; /* Restart beacon loss timer and requeue BSS loss work. */ RK960_DEBUG_SCAN("[CQM] Requeue BSS loss in %d " "beacons.\n", tmo); spin_lock(&priv->bss_loss_lock); priv->bss_loss_status = RK960_BSS_LOSS_NONE; spin_unlock(&priv->bss_loss_lock); cancel_delayed_work_sync(&priv->bss_loss_work); queue_delayed_work(hw_priv->workqueue, &priv->bss_loss_work, tmo * HZ / 10); } /* FW bug: driver has to restart p2p-dev mode after scan. */ if (priv->join_status == RK960_JOIN_STATUS_MONITOR) { /*rk960_enable_listening(priv); */ WARN_ON(1); rk960_update_filtering(priv); } if (hw_priv->delayed_unjoin_if_id != -1) { struct rk960_vif *priv2 = rk960_hwpriv_to_vifpriv(hw_priv, hw_priv-> delayed_unjoin_if_id); hw_priv->delayed_unjoin_if_id = -1; if (priv2) { rk960_priv_vif_list_read_unlock(&priv2->vif_lock); if (priv2->delayed_unjoin) { priv2->delayed_unjoin = false; RK960_DEBUG_SCAN("%s: unjoin_work %d\n", __func__, priv2->if_id); if (queue_work (hw_priv->workqueue, &priv2->unjoin_work) <= 0) wsm_unlock_tx(hw_priv); } } } } static void rk960_scan_complete(struct rk960_common *hw_priv, int if_id) { struct rk960_vif *priv; atomic_xchg(&hw_priv->recent_scan, 0); if (hw_priv->scan.direct_probe) { mutex_lock(&hw_priv->conf_mutex); priv = __rk960_hwpriv_to_vifpriv(hw_priv, if_id); if (priv) { RK960_DEBUG_SCAN("[SCAN] Direct probe " "complete.\n"); rk960_scan_restart_delayed(priv); } else { RK960_DEBUG_SCAN("[SCAN] Direct probe " "complete without interface!\n"); } mutex_unlock(&hw_priv->conf_mutex); hw_priv->scan.direct_probe = 0; up(&hw_priv->scan.lock); wsm_unlock_tx(hw_priv); } else { rk960_scan_work(&hw_priv->scan.work); } } void rk960_scan_complete_cb(struct rk960_common *hw_priv, struct wsm_scan_complete *arg) { struct rk960_vif *priv = rk960_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); if (unlikely(!priv)) return; #ifdef ROAM_OFFLOAD if (hw_priv->auto_scanning) queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); #endif /*ROAM_OFFLOAD */ if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) { /* STA is stopped. */ rk960_priv_vif_list_read_unlock(&priv->vif_lock); return; } rk960_priv_vif_list_read_unlock(&priv->vif_lock); if (hw_priv->scan.status == -ETIMEDOUT) RK960_INFO_SCAN ("Scan timeout already occured. Don't cancel work"); if ((hw_priv->scan.status != -ETIMEDOUT) && (cancel_delayed_work_sync(&hw_priv->scan.timeout) > 0)) { hw_priv->scan.status = 1; queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.timeout, 0); } } void rk960_scan_timeout(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, scan.timeout.work); #ifdef RK960_CSYNC_ADJUST rk960_csync_scan_complete(hw_priv); #endif if (likely(atomic_xchg(&hw_priv->scan.in_progress, 0))) { if (hw_priv->scan.status > 0) hw_priv->scan.status = 0; else if (!hw_priv->scan.status) { RK960_INFO_SCAN("Timeout waiting for scan " "complete notification.\n"); hw_priv->scan.status = -ETIMEDOUT; hw_priv->scan.curr = hw_priv->scan.end; WARN_ON(wsm_stop_scan(hw_priv, hw_priv->scan.if_id ? 1 : 0)); } rk960_scan_complete(hw_priv, hw_priv->scan.if_id); #ifdef ROAM_OFFLOAD } else if (hw_priv->auto_scanning) { hw_priv->auto_scanning = 0; ieee80211_sched_scan_results(hw_priv->hw); #endif /*ROAM_OFFLOAD */ } } #ifdef CONFIG_RK960_TESTMODE void rk960_advance_scan_timeout(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, advance_scan_timeout.work); struct rk960_vif *priv = rk960_hwpriv_to_vifpriv(hw_priv, hw_priv->scan.if_id); if (WARN_ON(!priv)) return; rk960_priv_vif_list_read_unlock(&priv->vif_lock); hw_priv->scan.status = 0; if (hw_priv->advanceScanElems.scanMode == RK960_SCAN_MEASUREMENT_PASSIVE) { /* Passive Scan on Serving Channel * Timer Expire */ rk960_scan_complete(hw_priv, hw_priv->scan.if_id); } else { #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) struct cfg80211_scan_info info = { .aborted = false, }; #endif /* Active Scan on Serving Channel * Timer Expire */ mutex_lock(&hw_priv->conf_mutex); //wsm_lock_tx(priv); wsm_vif_lock_tx(priv); /* Once Duration is Over, enable filtering * and Revert Back Power Save */ if ((priv->powersave_mode.pmMode & WSM_PSM_PS)) wsm_set_pm(hw_priv, &priv->powersave_mode, priv->if_id); hw_priv->scan.req = NULL; rk960_update_filtering(priv); hw_priv->enable_advance_scan = false; wsm_unlock_tx(hw_priv); mutex_unlock(&hw_priv->conf_mutex); #if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 6, 0)) ieee80211_scan_completed(hw_priv->hw, &info); #else ieee80211_scan_completed(hw_priv->hw, hw_priv->scan.status ? true : false); #endif up(&hw_priv->scan.lock); } } #endif void rk960_probe_work(struct work_struct *work) { struct rk960_common *hw_priv = container_of(work, struct rk960_common, scan.probe_work.work); struct rk960_vif *priv, *vif; u8 queueId = rk960_queue_get_queue_id(hw_priv->pending_frame_id); struct rk960_queue *queue = &hw_priv->tx_queue[queueId]; const struct rk960_txpriv *txpriv; struct wsm_tx *wsm; struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, }; struct wsm_ssid ssids[1] = { { .length = 0, } }; struct wsm_scan_ch ch[1] = { { #ifdef SCAN_TIME_ADJUST .minChannelTime = 50, .maxChannelTime = 110, #else .minChannelTime = 0, .maxChannelTime = 10, #endif } }; struct wsm_scan scan = { .scanType = WSM_SCAN_TYPE_FOREGROUND, .numOfProbeRequests = 1, .probeDelay = 0, .numOfChannels = 1, .ssids = ssids, .ch = ch, }; u8 *ies; size_t ies_len; int ret = 1; int i; RK960_DEBUG_SCAN("[SCAN] Direct probe work.\n"); BUG_ON(queueId >= 4); BUG_ON(!hw_priv->channel); mutex_lock(&hw_priv->conf_mutex); if (unlikely(down_trylock(&hw_priv->scan.lock))) { /* Scan is already in progress. Requeue self. */ schedule(); queue_delayed_work(hw_priv->workqueue, &hw_priv->scan.probe_work, HZ / 10); mutex_unlock(&hw_priv->conf_mutex); return; } if (rk960_queue_get_skb(queue, hw_priv->pending_frame_id, &frame.skb, &txpriv)) { up(&hw_priv->scan.lock); mutex_unlock(&hw_priv->conf_mutex); wsm_unlock_tx(hw_priv); return; } priv = __rk960_hwpriv_to_vifpriv(hw_priv, txpriv->if_id); if (!priv) { up(&hw_priv->scan.lock); mutex_unlock(&hw_priv->conf_mutex); return; } wsm = (struct wsm_tx *)frame.skb->data; scan.maxTransmitRate = wsm->maxTxRate; scan.band = (hw_priv->channel->band == IEEE80211_BAND_5GHZ) ? WSM_PHY_BAND_5G : WSM_PHY_BAND_2_4G; if (priv->join_status == RK960_JOIN_STATUS_STA) { scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.scanFlags = WSM_SCAN_FLAG_FORCE_BACKGROUND; if (priv->if_id) scan.scanFlags |= WSM_FLAG_MAC_INSTANCE_1; else scan.scanFlags &= ~WSM_FLAG_MAC_INSTANCE_1; } //rk960_for_each_vif(hw_priv, vif, i) { for (i = 0; i < RK960_MAX_VIFS; i++) { vif = hw_priv->vif_list[i] ? rk960_get_vif_from_ieee80211(hw_priv->vif_list[i]) : NULL; if (!vif) continue; if (vif->bss_loss_status > RK960_BSS_LOSS_NONE) scan.scanFlags |= WSM_SCAN_FLAG_FORCE_BACKGROUND; } ch[0].number = hw_priv->channel->hw_value; skb_pull(frame.skb, txpriv->offset); ies = &frame.skb->data[sizeof(struct ieee80211_hdr_3addr)]; ies_len = frame.skb->len - sizeof(struct ieee80211_hdr_3addr); if (ies_len) { u8 *ssidie = (u8 *) cfg80211_find_ie(WLAN_EID_SSID, ies, ies_len); if (ssidie && ssidie[1] && ssidie[1] <= sizeof(ssids[0].ssid)) { u8 *nextie = &ssidie[2 + ssidie[1]]; /* Remove SSID from the IE list. It has to be provided * as a separate argument in rk960_scan_start call */ /* Store SSID localy */ ssids[0].length = ssidie[1]; memcpy(ssids[0].ssid, &ssidie[2], ssids[0].length); scan.numOfSSIDs = 1; /* Remove SSID from IE list */ ssidie[1] = 0; memmove(&ssidie[2], nextie, &ies[ies_len] - nextie); skb_trim(frame.skb, frame.skb->len - ssids[0].length); } } if (priv->if_id == 0) rk960_remove_wps_p2p_ie(&frame); /* FW bug: driver has to restart p2p-dev mode after scan */ if (priv->join_status == RK960_JOIN_STATUS_MONITOR) { WARN_ON(1); /*rk960_disable_listening(priv); */ } ret = WARN_ON(wsm_set_template_frame(hw_priv, &frame, priv->if_id)); hw_priv->scan.direct_probe = 1; hw_priv->scan.if_id = priv->if_id; if (!ret) { wsm_flush_tx(hw_priv); ret = WARN_ON(rk960_scan_start(priv, &scan)); } mutex_unlock(&hw_priv->conf_mutex); skb_push(frame.skb, txpriv->offset); if (!ret) IEEE80211_SKB_CB(frame.skb)->flags |= IEEE80211_TX_STAT_ACK; #ifdef CONFIG_RK960_TESTMODE BUG_ON(rk960_queue_remove(hw_priv, queue, hw_priv->pending_frame_id)); #else BUG_ON(rk960_queue_remove(queue, hw_priv->pending_frame_id)); #endif if (ret) { hw_priv->scan.direct_probe = 0; up(&hw_priv->scan.lock); wsm_unlock_tx(hw_priv); } return; } static struct sk_buff *ieee80211_probereq_get_rftest(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const u8 * ssid, size_t ssid_len, size_t total_len) { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local; struct ieee80211_hdr_3addr *hdr; struct sk_buff *skb; size_t ie_ssid_len; int data_len; u8 *pos; data_len = total_len - sizeof(*hdr) - ssid_len; sdata = vif_to_sdata(vif); local = sdata->local; ie_ssid_len = 2 + ssid_len; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*hdr) + ie_ssid_len + data_len + 8); if (!skb) return NULL; skb_reserve(skb, local->hw.extra_tx_headroom); hdr = (struct ieee80211_hdr_3addr *)skb_put(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ); memset(hdr->addr1, 0xff, ETH_ALEN); memcpy(hdr->addr2, vif->addr, ETH_ALEN); memset(hdr->addr3, 0xff, ETH_ALEN); pos = skb_put(skb, ie_ssid_len); *pos++ = 0; *pos++ = ssid_len; if (ssid) memcpy(pos, ssid, ssid_len); pos += ssid_len; while (1) { pos = skb_put(skb, 8); *pos++ = 221; *pos++ = 6; pos += 6; data_len -= 8; if (data_len < 0) break; } return skb; } int rk960_rftest_start_tx(struct rk960_common *hw_priv, int channel, int rate, int tx_power, int len, int count, int sgi) { int ret = 0; struct wsm_template_frame frame = { .frame_type = WSM_FRAME_TYPE_PROBE_REQUEST, }; struct ieee80211_vif *vif = hw_priv->vif_list[hw_priv->def_vif_id]; struct wsm_scan scan; struct wsm_ssid ssids; struct wsm_scan_ch ch[1]; rk960_rftest_stop_txrx(hw_priv); WARN_ON(wsm_set_output_power(hw_priv, tx_power, 0)); frame.skb = ieee80211_probereq_get_rftest(hw_priv->hw, vif, "tttttttt", 8, 200); //RK960_INFO_SCAN("%s: frame len %d\n", __func__, frame.skb->len); ret = wsm_set_template_frame(hw_priv, &frame, 0); if (frame.skb) dev_kfree_skb(frame.skb); if (ret) return ret; hw_priv->scan.if_id = hw_priv->def_vif_id; memset(&scan, 0, sizeof(struct wsm_scan)); scan.scanFlags = 0; scan.maxTransmitRate = rate; if (sgi > 0) scan.maxTransmitRate |= 1 << 7; if (!count) { scan.autoScanInterval = (0xFFFF << 16) | len; } else { scan.autoScanInterval = (count << 16) | len; } scan.numOfProbeRequests = 0xff; scan.numOfChannels = 1; scan.numOfSSIDs = 1; scan.probeDelay = 1; scan.scanType = WSM_SCAN_TYPE_FOREGROUND; scan.ssids = &ssids; scan.ssids->length = 4; memcpy(ssids.ssid, "tttt", 4); scan.ch = &ch[0]; scan.ch[0].number = channel; scan.ch[0].minChannelTime = 10; scan.ch[0].maxChannelTime = 11; scan.ch[0].txPowerLevel = 3; hw_priv->rftest_scan = 1; return wsm_scan(hw_priv, &scan, hw_priv->def_vif_id); } int rk960_rftest_start_rx(struct rk960_common *hw_priv, int channel) { struct wsm_scan scan; struct wsm_ssid ssids; struct wsm_scan_ch ch[1]; int monitor = channel & 0x80; channel &= ~0x80; rk960_rftest_stop_txrx(hw_priv); hw_priv->scan.if_id = hw_priv->def_vif_id; memset(&scan, 0, sizeof(struct wsm_scan)); scan.scanFlags = 0; scan.maxTransmitRate = 0; scan.autoScanInterval = (0xba << 24) | (30 * 1024); if (monitor) scan.numOfProbeRequests = 0xfd; else scan.numOfProbeRequests = 0xfe; scan.numOfChannels = 1; scan.numOfSSIDs = 1; scan.probeDelay = 1; scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.ssids = &ssids; scan.ssids->length = 4; memcpy(ssids.ssid, "tttt", 4); scan.ch = &ch[0]; scan.ch[0].number = channel; scan.ch[0].minChannelTime = 10; scan.ch[0].maxChannelTime = 0x7fffffff / 1024; scan.ch[0].txPowerLevel = 3; hw_priv->rftest_scan = 1; return wsm_scan(hw_priv, &scan, hw_priv->def_vif_id); } int rk960_rftest_start_tone(struct rk960_common *hw_priv, int channel, int tone) { struct wsm_scan scan; struct wsm_ssid ssids; struct wsm_scan_ch ch[1]; rk960_rftest_stop_txrx(hw_priv); hw_priv->scan.if_id = hw_priv->def_vif_id; memset(&scan, 0, sizeof(struct wsm_scan)); scan.scanFlags = 0; scan.maxTransmitRate = 0; scan.autoScanInterval = channel; if (tone) scan.numOfProbeRequests = 0xfc; else scan.numOfProbeRequests = 0xfb; scan.numOfChannels = 1; scan.numOfSSIDs = 1; scan.probeDelay = 1; scan.scanType = WSM_SCAN_TYPE_BACKGROUND; scan.ssids = &ssids; scan.ssids->length = 4; memcpy(ssids.ssid, "tttt", 4); scan.ch = &ch[0]; scan.ch[0].number = channel; scan.ch[0].minChannelTime = 10; scan.ch[0].maxChannelTime = 0x7fffffff / 1024; scan.ch[0].txPowerLevel = 3; hw_priv->rftest_scan = 1; return wsm_scan(hw_priv, &scan, hw_priv->def_vif_id); } int rk960_rftest_stop_txrx(struct rk960_common *hw_priv) { if (!hw_priv->rftest_scan) return 0; hw_priv->rftest_scan = 0; return wsm_stop_scan(hw_priv, hw_priv->def_vif_id); }