|
@@ -488,8 +488,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar)
|
|
|
static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
|
|
{
|
|
|
struct ath10k *ar = arvif->ar;
|
|
|
- struct ieee80211_conf *conf = &ar->hw->conf;
|
|
|
- struct ieee80211_channel *channel = conf->chandef.chan;
|
|
|
+ struct cfg80211_chan_def *chandef = &ar->chandef;
|
|
|
struct wmi_vdev_start_request_arg arg = {};
|
|
|
int ret = 0;
|
|
|
|
|
@@ -501,16 +500,14 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
|
|
arg.dtim_period = arvif->dtim_period;
|
|
|
arg.bcn_intval = arvif->beacon_interval;
|
|
|
|
|
|
- arg.channel.freq = channel->center_freq;
|
|
|
-
|
|
|
- arg.channel.band_center_freq1 = conf->chandef.center_freq1;
|
|
|
-
|
|
|
- arg.channel.mode = chan_to_phymode(&conf->chandef);
|
|
|
+ arg.channel.freq = chandef->chan->center_freq;
|
|
|
+ arg.channel.band_center_freq1 = chandef->center_freq1;
|
|
|
+ arg.channel.mode = chan_to_phymode(chandef);
|
|
|
|
|
|
arg.channel.min_power = 0;
|
|
|
- arg.channel.max_power = channel->max_power * 2;
|
|
|
- arg.channel.max_reg_power = channel->max_reg_power * 2;
|
|
|
- arg.channel.max_antenna_gain = channel->max_antenna_gain * 2;
|
|
|
+ arg.channel.max_power = chandef->chan->max_power * 2;
|
|
|
+ arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
|
|
|
+ arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
|
|
|
|
|
|
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
|
arg.ssid = arvif->u.ap.ssid;
|
|
@@ -519,7 +516,7 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
|
|
|
|
|
|
/* For now allow DFS for AP mode */
|
|
|
arg.channel.chan_radar =
|
|
|
- !!(channel->flags & IEEE80211_CHAN_RADAR);
|
|
|
+ !!(chandef->chan->flags & IEEE80211_CHAN_RADAR);
|
|
|
} else if (arvif->vdev_type == WMI_VDEV_TYPE_IBSS) {
|
|
|
arg.ssid = arvif->vif->bss_conf.ssid;
|
|
|
arg.ssid_len = arvif->vif->bss_conf.ssid_len;
|
|
@@ -571,7 +568,8 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
|
|
|
|
|
|
static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
|
|
|
{
|
|
|
- struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
|
|
|
+ struct cfg80211_chan_def *chandef = &ar->chandef;
|
|
|
+ struct ieee80211_channel *channel = chandef->chan;
|
|
|
struct wmi_vdev_start_request_arg arg = {};
|
|
|
int ret = 0;
|
|
|
|
|
@@ -584,11 +582,11 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
|
|
|
|
|
|
arg.vdev_id = vdev_id;
|
|
|
arg.channel.freq = channel->center_freq;
|
|
|
- arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
|
|
|
+ arg.channel.band_center_freq1 = chandef->center_freq1;
|
|
|
|
|
|
/* TODO setup this dynamically, what in case we
|
|
|
don't have any vifs? */
|
|
|
- arg.channel.mode = chan_to_phymode(&ar->hw->conf.chandef);
|
|
|
+ arg.channel.mode = chan_to_phymode(chandef);
|
|
|
arg.channel.chan_radar =
|
|
|
!!(channel->flags & IEEE80211_CHAN_RADAR);
|
|
|
|
|
@@ -835,6 +833,10 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
|
|
|
|
|
|
if (!info->enable_beacon) {
|
|
|
ath10k_vdev_stop(arvif);
|
|
|
+
|
|
|
+ arvif->is_started = false;
|
|
|
+ arvif->is_up = false;
|
|
|
+
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -844,12 +846,21 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
|
|
|
if (ret)
|
|
|
return;
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, 0, info->bssid);
|
|
|
+ arvif->aid = 0;
|
|
|
+ memcpy(arvif->bssid, info->bssid, ETH_ALEN);
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
|
|
+ arvif->bssid);
|
|
|
if (ret) {
|
|
|
ath10k_warn("Failed to bring up VDEV: %d\n",
|
|
|
arvif->vdev_id);
|
|
|
+ ath10k_vdev_stop(arvif);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ arvif->is_started = true;
|
|
|
+ arvif->is_up = true;
|
|
|
+
|
|
|
ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
|
|
|
}
|
|
|
|
|
@@ -868,18 +879,18 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
|
|
|
ath10k_warn("Failed to delete IBSS self peer:%pM for VDEV:%d ret:%d\n",
|
|
|
self_peer, arvif->vdev_id, ret);
|
|
|
|
|
|
- if (is_zero_ether_addr(arvif->u.ibss.bssid))
|
|
|
+ if (is_zero_ether_addr(arvif->bssid))
|
|
|
return;
|
|
|
|
|
|
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id,
|
|
|
- arvif->u.ibss.bssid);
|
|
|
+ arvif->bssid);
|
|
|
if (ret) {
|
|
|
ath10k_warn("Failed to delete IBSS BSSID peer:%pM for VDEV:%d ret:%d\n",
|
|
|
- arvif->u.ibss.bssid, arvif->vdev_id, ret);
|
|
|
+ arvif->bssid, arvif->vdev_id, ret);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- memset(arvif->u.ibss.bssid, 0, ETH_ALEN);
|
|
|
+ memset(arvif->bssid, 0, ETH_ALEN);
|
|
|
|
|
|
return;
|
|
|
}
|
|
@@ -1387,11 +1398,17 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
|
|
|
"mac vdev %d up (associated) bssid %pM aid %d\n",
|
|
|
arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
|
|
|
|
|
|
- ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
|
|
|
- bss_conf->bssid);
|
|
|
- if (ret)
|
|
|
+ arvif->aid = bss_conf->aid;
|
|
|
+ memcpy(arvif->bssid, bss_conf->bssid, ETH_ALEN);
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, arvif->aid, arvif->bssid);
|
|
|
+ if (ret) {
|
|
|
ath10k_warn("VDEV: %d up failed: ret %d\n",
|
|
|
arvif->vdev_id, ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ arvif->is_up = true;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1431,6 +1448,9 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
|
|
|
ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
|
|
|
|
|
|
arvif->def_wep_key_idx = 0;
|
|
|
+
|
|
|
+ arvif->is_started = false;
|
|
|
+ arvif->is_up = false;
|
|
|
}
|
|
|
|
|
|
static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
|
|
@@ -2201,6 +2221,98 @@ static int ath10k_config_ps(struct ath10k *ar)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static const char *chandef_get_width(enum nl80211_chan_width width)
|
|
|
+{
|
|
|
+ switch (width) {
|
|
|
+ case NL80211_CHAN_WIDTH_20_NOHT:
|
|
|
+ return "20 (noht)";
|
|
|
+ case NL80211_CHAN_WIDTH_20:
|
|
|
+ return "20";
|
|
|
+ case NL80211_CHAN_WIDTH_40:
|
|
|
+ return "40";
|
|
|
+ case NL80211_CHAN_WIDTH_80:
|
|
|
+ return "80";
|
|
|
+ case NL80211_CHAN_WIDTH_80P80:
|
|
|
+ return "80+80";
|
|
|
+ case NL80211_CHAN_WIDTH_160:
|
|
|
+ return "160";
|
|
|
+ case NL80211_CHAN_WIDTH_5:
|
|
|
+ return "5";
|
|
|
+ case NL80211_CHAN_WIDTH_10:
|
|
|
+ return "10";
|
|
|
+ }
|
|
|
+ return "?";
|
|
|
+}
|
|
|
+
|
|
|
+static void ath10k_config_chan(struct ath10k *ar)
|
|
|
+{
|
|
|
+ struct ath10k_vif *arvif;
|
|
|
+ bool monitor_was_enabled;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ lockdep_assert_held(&ar->conf_mutex);
|
|
|
+
|
|
|
+ ath10k_dbg(ATH10K_DBG_MAC,
|
|
|
+ "mac config channel to %dMHz (cf1 %dMHz cf2 %dMHz width %s)\n",
|
|
|
+ ar->chandef.chan->center_freq,
|
|
|
+ ar->chandef.center_freq1,
|
|
|
+ ar->chandef.center_freq2,
|
|
|
+ chandef_get_width(ar->chandef.width));
|
|
|
+
|
|
|
+ /* First stop monitor interface. Some FW versions crash if there's a
|
|
|
+ * lone monitor interface. */
|
|
|
+ monitor_was_enabled = ar->monitor_enabled;
|
|
|
+
|
|
|
+ if (ar->monitor_enabled)
|
|
|
+ ath10k_monitor_stop(ar);
|
|
|
+
|
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
|
+ if (!arvif->is_started)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = ath10k_vdev_stop(arvif);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not stop vdev %d (%d)\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* all vdevs are now stopped - now attempt to restart them */
|
|
|
+
|
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
|
+ if (!arvif->is_started)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (arvif->vdev_type == WMI_VDEV_TYPE_MONITOR)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = ath10k_vdev_start(arvif);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not start vdev %d (%d)\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!arvif->is_up)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ ret = ath10k_wmi_vdev_up(arvif->ar, arvif->vdev_id, arvif->aid,
|
|
|
+ arvif->bssid);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("could not bring vdev up %d (%d)\n",
|
|
|
+ arvif->vdev_id, ret);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (monitor_was_enabled)
|
|
|
+ ath10k_monitor_start(ar, ar->monitor_vdev_id);
|
|
|
+}
|
|
|
+
|
|
|
static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
{
|
|
|
struct ath10k *ar = hw->priv;
|
|
@@ -2221,6 +2333,11 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
|
|
|
spin_unlock_bh(&ar->data_lock);
|
|
|
|
|
|
ath10k_config_radar_detection(ar);
|
|
|
+
|
|
|
+ if (!cfg80211_chandef_identical(&ar->chandef, &conf->chandef)) {
|
|
|
+ ar->chandef = conf->chandef;
|
|
|
+ ath10k_config_chan(ar);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (changed & IEEE80211_CONF_CHANGE_POWER) {
|
|
@@ -2615,15 +2732,20 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
* this is never erased as we it for crypto key
|
|
|
* clearing; this is FW requirement
|
|
|
*/
|
|
|
- memcpy(arvif->u.sta.bssid, info->bssid,
|
|
|
- ETH_ALEN);
|
|
|
+ memcpy(arvif->bssid, info->bssid, ETH_ALEN);
|
|
|
|
|
|
ath10k_dbg(ATH10K_DBG_MAC,
|
|
|
"mac vdev %d start %pM\n",
|
|
|
arvif->vdev_id, info->bssid);
|
|
|
|
|
|
- /* FIXME: check return value */
|
|
|
ret = ath10k_vdev_start(arvif);
|
|
|
+ if (ret) {
|
|
|
+ ath10k_warn("failed to start vdev: %d\n",
|
|
|
+ ret);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ arvif->is_started = true;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2632,7 +2754,7 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
|
|
|
* IBSS in order to remove BSSID peer.
|
|
|
*/
|
|
|
if (vif->type == NL80211_IFTYPE_ADHOC)
|
|
|
- memcpy(arvif->u.ibss.bssid, info->bssid,
|
|
|
+ memcpy(arvif->bssid, info->bssid,
|
|
|
ETH_ALEN);
|
|
|
}
|
|
|
}
|