@@ -51,6 +51,7 @@
#include "src/mpdu.h"
#include "src/band.h"
#include "src/scan.h"
+#include "src/blacklist.h"
/* User configurable options */
static double RANK_2G_FACTOR;
@@ -58,6 +59,7 @@ static double RANK_5G_FACTOR;
static double RANK_6G_FACTOR;
static uint32_t RANK_HIGH_UTILIZATION;
static uint32_t RANK_HIGH_STATION_COUNT;
+static int RANK_OPTIMAL_SIGNAL_THRESHOLD;
static uint32_t SCAN_MAX_INTERVAL;
static uint32_t SCAN_INIT_INTERVAL;
@@ -1910,15 +1912,41 @@ int scan_bss_get_security(const struct scan_bss *bss, enum security *security)
return 0;
}
+/*
+ * Evaluate the BSS's grouping based on its signal strength and blacklist
+ * status. From best to worst the groupings are:
+ *
+ * Optimal: Not blacklisted in any form, and above the RSSI threshold
+ * Above Threshold: Above the RSSI threshold (may be roam blacklisted)
+ * Below Threshold: Below the RSSI threshold (may be roam blacklisted)
+ * Blacklisted: Permanently blacklisted
+ */
+enum scan_bss_group scan_bss_evaluate_group(const uint8_t *addr,
+ int16_t signal_strength)
+{
+ int rssi = signal_strength / 100;
+
+ if (RANK_OPTIMAL_SIGNAL_THRESHOLD == 0)
+ return SCAN_BSS_GROUP_OPTIMAL;
+
+ if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
+ return SCAN_BSS_GROUP_BLACKLISTED;
+
+ if (!blacklist_contains_bss(addr, BLACKLIST_REASON_ROAM_REQUESTED) &&
+ rssi >= RANK_OPTIMAL_SIGNAL_THRESHOLD)
+ return SCAN_BSS_GROUP_OPTIMAL;
+
+ if (rssi >= RANK_OPTIMAL_SIGNAL_THRESHOLD)
+ return SCAN_BSS_GROUP_ABOVE_THRESHOLD;
+
+ return SCAN_BSS_GROUP_UNDER_THRESHOLD;
+}
+
int scan_bss_rank_compare(const void *a, const void *b, void *user_data)
{
const struct scan_bss *new_bss = a, *bss = b;
- if (bss->rank == new_bss->rank)
- return (bss->signal_strength >
- new_bss->signal_strength) ? 1 : -1;
-
- return (bss->rank > new_bss->rank) ? 1 : -1;
+ return __scan_bss_rank_compare(new_bss, bss);
}
static bool scan_survey_get_snr(struct scan_results *results,
@@ -2678,6 +2706,10 @@ static int scan_init(void)
if (L_WARN_ON(RANK_HIGH_STATION_COUNT > 255))
RANK_HIGH_STATION_COUNT = 255;
+ if (!l_settings_get_int(config, "General", "OptimalSignalThreshold",
+ &RANK_OPTIMAL_SIGNAL_THRESHOLD))
+ RANK_OPTIMAL_SIGNAL_THRESHOLD = 0;
+
return 0;
}
@@ -45,6 +45,17 @@ enum scan_bss_frame_type {
SCAN_BSS_BEACON,
};
+/*
+ * Groupings for BSS's. These are assumed to be in order of preference where
+ * the last enum is the most preferred group to connect to.
+ */
+enum scan_bss_group {
+ SCAN_BSS_GROUP_BLACKLISTED,
+ SCAN_BSS_GROUP_UNDER_THRESHOLD,
+ SCAN_BSS_GROUP_ABOVE_THRESHOLD,
+ SCAN_BSS_GROUP_OPTIMAL,
+};
+
struct scan_bss {
uint8_t addr[6];
uint32_t frequency;
@@ -168,6 +179,36 @@ bool scan_get_firmware_scan(uint64_t wdev_id, scan_notify_func_t notify,
void *userdata, scan_destroy_func_t destroy);
void scan_bss_free(struct scan_bss *bss);
+
+enum scan_bss_group scan_bss_evaluate_group(const uint8_t *addr,
+ int16_t signal_strength);
+
+/*
+ * Macro to compare two scan_bss-like objects. This is to share code between
+ * station.c and scan.c since station uses "roam_bss" objects which is a subset
+ * of a scan_bss.
+ * - If the groups differ this is used as the comparison.
+ * - If the groups match, the BSS rank is used as the comparison
+ * - If the BSS ranks match, the signal strength is used as the comparison
+ */
+#define __scan_bss_rank_compare(a, b) ({ \
+ int ret; \
+ enum scan_bss_group a_group = scan_bss_evaluate_group( \
+ (a)->addr, (a)->signal_strength); \
+ enum scan_bss_group b_group = scan_bss_evaluate_group( \
+ (b)->addr, (b)->signal_strength); \
+ if (b_group > a_group) \
+ ret = 1; \
+ else if (b_group < a_group) \
+ ret = -1; \
+ else if ((b)->rank == (a)->rank) \
+ ret = ((b)->signal_strength > \
+ (a)->signal_strength) ? 1 : -1; \
+ else \
+ ret = ((b)->rank > (a)->rank) ? 1 : -1; \
+ ret; \
+})
+
int scan_bss_rank_compare(const void *a, const void *b, void *user);
int scan_bss_get_rsn_info(const struct scan_bss *bss, struct ie_rsn_info *info);