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:
parent
30d32e4a58
commit
befa448017
192
src/netdev.c
192
src/netdev.c
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user