3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-26 02:19:26 +01:00

netdev: fix RoamThreshold5G

The RoamThreshold5G was never honored because it was being
set prior to any connections. This caused the logic inside
netdev_cqm_rssi_update to always choose the 2GHz threshold
(RoamThreshold) due to netdev->frequency being zero at this time.

Instead call netdev_cqm_rssi_update in all connect/transition
calls after netdev->frequency is updated. This will allow both
the 2G and 5G thresholds to be used depending on what frequency
the new BSS is.

The call to netdev_cqm_rssi_update in netdev_setup_interface
was also removed since it serves no purpose, at least now
that there are two thresholds to consider.
This commit is contained in:
James Prestwood 2021-07-27 15:50:23 -07:00 committed by Denis Kenzior
parent 30d32e4a58
commit befa448017

View File

@ -3161,6 +3161,100 @@ static int netdev_start_powered_mac_change(struct netdev *netdev)
return 0; return 0;
} }
static struct l_genl_msg *netdev_build_cmd_cqm_rssi_update(
struct netdev *netdev,
const int8_t *levels,
size_t levels_num)
{
struct l_genl_msg *msg;
uint32_t hyst = 5;
int thold_count;
int32_t thold_list[levels_num + 2];
int threshold = netdev->frequency > 4000 ? LOW_SIGNAL_THRESHOLD_5GHZ :
LOW_SIGNAL_THRESHOLD;
if (levels_num == 0) {
thold_list[0] = threshold;
thold_count = 1;
} else {
/*
* Build the list of all the threshold values we care about:
* - the low/high level threshold,
* - the value ranges requested by
* netdev_set_rssi_report_levels
*/
unsigned int i;
bool low_sig_added = false;
thold_count = 0;
for (i = 0; i < levels_num; i++) {
int32_t val = levels[levels_num - i - 1];
if (i && thold_list[thold_count - 1] >= val)
return NULL;
if (val >= threshold && !low_sig_added) {
thold_list[thold_count++] = threshold;
low_sig_added = true;
/* Duplicate values are not allowed */
if (val == threshold)
continue;
}
thold_list[thold_count++] = val;
}
}
msg = l_genl_msg_new_sized(NL80211_CMD_SET_CQM, 32 + thold_count * 4);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_enter_nested(msg, NL80211_ATTR_CQM);
l_genl_msg_append_attr(msg, NL80211_ATTR_CQM_RSSI_THOLD,
thold_count * 4, thold_list);
l_genl_msg_append_attr(msg, NL80211_ATTR_CQM_RSSI_HYST, 4, &hyst);
l_genl_msg_leave_nested(msg);
return msg;
}
static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
{
int err = l_genl_msg_get_error(msg);
const char *ext_error;
if (err >= 0)
return;
ext_error = l_genl_msg_get_extended_error(msg);
l_error("CMD_SET_CQM failed: %s",
ext_error ? ext_error : strerror(-err));
}
static int netdev_cqm_rssi_update(struct netdev *netdev)
{
struct l_genl_msg *msg;
l_debug("");
if (!wiphy_has_ext_feature(netdev->wiphy,
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
msg = netdev_build_cmd_cqm_rssi_update(netdev, NULL, 0);
else
msg = netdev_build_cmd_cqm_rssi_update(netdev,
netdev->rssi_levels,
netdev->rssi_levels_num);
if (!msg)
return -EINVAL;
if (!l_genl_family_send(nl80211, msg, netdev_cmd_set_cqm_cb,
NULL, NULL)) {
l_genl_msg_unref(msg);
return -EIO;
}
return 0;
}
static bool netdev_connection_work_ready(struct wiphy_radio_work_item *item) static bool netdev_connection_work_ready(struct wiphy_radio_work_item *item)
{ {
struct netdev *netdev = l_container_of(item, struct netdev, work); struct netdev *netdev = l_container_of(item, struct netdev, work);
@ -3309,6 +3403,7 @@ static int netdev_connect_common(struct netdev *netdev,
netdev->frequency = bss->frequency; netdev->frequency = bss->frequency;
netdev->cur_rssi = bss->signal_strength / 100; netdev->cur_rssi = bss->signal_strength / 100;
netdev_rssi_level_init(netdev); netdev_rssi_level_init(netdev);
netdev_cqm_rssi_update(netdev);
handshake_state_set_authenticator_address(hs, bss->addr); handshake_state_set_authenticator_address(hs, bss->addr);
@ -3804,6 +3899,7 @@ static void prepare_ft(struct netdev *netdev, struct scan_bss *target_bss)
} }
netdev_rssi_polling_update(netdev); netdev_rssi_polling_update(netdev);
netdev_cqm_rssi_update(netdev);
if (netdev->sm) { if (netdev->sm) {
eapol_sm_free(netdev->sm); eapol_sm_free(netdev->sm);
@ -4904,75 +5000,6 @@ static void netdev_unicast_notify(struct l_genl_msg *msg, void *user_data)
} }
} }
static struct l_genl_msg *netdev_build_cmd_cqm_rssi_update(
struct netdev *netdev,
const int8_t *levels,
size_t levels_num)
{
struct l_genl_msg *msg;
uint32_t hyst = 5;
int thold_count;
int32_t thold_list[levels_num + 2];
int threshold = netdev->frequency > 4000 ? LOW_SIGNAL_THRESHOLD_5GHZ :
LOW_SIGNAL_THRESHOLD;
if (levels_num == 0) {
thold_list[0] = threshold;
thold_count = 1;
} else {
/*
* Build the list of all the threshold values we care about:
* - the low/high level threshold,
* - the value ranges requested by
* netdev_set_rssi_report_levels
*/
unsigned int i;
bool low_sig_added = false;
thold_count = 0;
for (i = 0; i < levels_num; i++) {
int32_t val = levels[levels_num - i - 1];
if (i && thold_list[thold_count - 1] >= val)
return NULL;
if (val >= threshold && !low_sig_added) {
thold_list[thold_count++] = threshold;
low_sig_added = true;
/* Duplicate values are not allowed */
if (val == threshold)
continue;
}
thold_list[thold_count++] = val;
}
}
msg = l_genl_msg_new_sized(NL80211_CMD_SET_CQM, 32 + thold_count * 4);
l_genl_msg_append_attr(msg, NL80211_ATTR_IFINDEX, 4, &netdev->index);
l_genl_msg_enter_nested(msg, NL80211_ATTR_CQM);
l_genl_msg_append_attr(msg, NL80211_ATTR_CQM_RSSI_THOLD,
thold_count * 4, thold_list);
l_genl_msg_append_attr(msg, NL80211_ATTR_CQM_RSSI_HYST, 4, &hyst);
l_genl_msg_leave_nested(msg);
return msg;
}
static void netdev_cmd_set_cqm_cb(struct l_genl_msg *msg, void *user_data)
{
int err = l_genl_msg_get_error(msg);
const char *ext_error;
if (err >= 0)
return;
ext_error = l_genl_msg_get_extended_error(msg);
l_error("CMD_SET_CQM failed: %s",
ext_error ? ext_error : strerror(-err));
}
int netdev_set_rssi_report_levels(struct netdev *netdev, const int8_t *levels, int netdev_set_rssi_report_levels(struct netdev *netdev, const int8_t *levels,
size_t levels_num) size_t levels_num)
{ {
@ -5131,31 +5158,6 @@ int netdev_get_all_stations(struct netdev *netdev, netdev_get_station_cb_t cb,
return 0; return 0;
} }
static int netdev_cqm_rssi_update(struct netdev *netdev)
{
struct l_genl_msg *msg;
l_debug("");
if (!wiphy_has_ext_feature(netdev->wiphy,
NL80211_EXT_FEATURE_CQM_RSSI_LIST))
msg = netdev_build_cmd_cqm_rssi_update(netdev, NULL, 0);
else
msg = netdev_build_cmd_cqm_rssi_update(netdev,
netdev->rssi_levels,
netdev->rssi_levels_num);
if (!msg)
return -EINVAL;
if (!l_genl_family_send(nl80211, msg, netdev_cmd_set_cqm_cb,
NULL, NULL)) {
l_genl_msg_unref(msg);
return -EIO;
}
return 0;
}
static void netdev_add_station_frame_watches(struct netdev *netdev) static void netdev_add_station_frame_watches(struct netdev *netdev)
{ {
static const uint8_t action_neighbor_report_prefix[2] = { 0x05, 0x05 }; static const uint8_t action_neighbor_report_prefix[2] = { 0x05, 0x05 };
@ -5192,8 +5194,6 @@ static void netdev_setup_interface(struct netdev *netdev)
{ {
switch (netdev->type) { switch (netdev->type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
/* Set RSSI threshold for CQM notifications */
netdev_cqm_rssi_update(netdev);
netdev_add_station_frame_watches(netdev); netdev_add_station_frame_watches(netdev);
break; break;
default: default: