diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..a9582eb1 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,269 @@ +name: IWD CI + +# +# The basic flow of the CI is as follows: +# +# 1. Get all inputs, or default values, and set as 'setup' job output +# 2. Find any cached binaries (hostapd, wpa_supplicant, kernel etc) +# 3. Checkout all dependent repositories +# 4. Tar all local files. This is an unfortunate requirement since github jobs +# cannot share local files. Since there are multiple CI's acting on the same +# set of repositories it makes more sense to retain these and re-download +# them for each CI job. +# 5. Run each CI, currently 'main' and 'musl'. +# * 'main' is the default IWD CI which runs all the build steps as well +# as test-runner +# * 'musl' uses an alpine docker image to test the build on musl-libc +# +# Both CI's use the 'iwd-ci' repo which calls into 'ci-docker'. The +# 'ci-docker' action essentially re-implements the native Github docker +# action but allows arbitrary options to be passed in (e.g. privileged or +# mounting non-standard directories) +# + +on: + pull_request: + workflow_dispatch: + inputs: + tests: + description: Tests to run (comma separated, no spaces) + default: all + kernel: + description: Kernel version + default: '6.2' + hostapd_version: + description: Hostapd and wpa_supplicant version + default: 'hostapd_2_11' + ell_ref: + description: ELL reference + default: refs/heads/workflow + + repository_dispatch: + types: [ell-dispatch] + +jobs: + setup: + runs-on: ubuntu-22.04 + outputs: + tests: ${{ steps.inputs.outputs.tests }} + kernel: ${{ steps.inputs.outputs.kernel }} + hostapd_version: ${{ steps.inputs.outputs.hostapd_version }} + ell_ref: ${{ steps.inputs.outputs.ell_ref }} + repository: ${{ steps.inputs.outputs.repository }} + ref_branch: ${{ steps.inputs.outputs.ref_branch }} + steps: + # + # This makes CI inputs consistent depending on how the CI was invoked: + # * pull_request trigger won't have any inputs, so these need to be set + # to default values. + # * workflow_dispatch sets all inputs from the user input + # * repository_dispatch sets all inputs based on the JSON payload of + # the request. + # + - name: Setup Inputs + id: inputs + run: | + if [ ${{ github.event_name }} == 'workflow_dispatch' ] + then + TESTS=${{ github.event.inputs.tests }} + KERNEL=${{ github.event.inputs.kernel }} + HOSTAPD_VERSION=${{ github.event.inputs.hostapd_version }} + ELL_REF=${{ github.event.inputs.ell_ref }} + REF="$GITHUB_REF" + REPO="$GITHUB_REPOSITORY" + elif [ ${{ github.event_name }} == 'repository_dispatch' ] + then + TESTS=all + KERNEL=5.19 + HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 + ELL_REF=${{ github.event.client_payload.ref }} + REF=$ELL_REF + REPO=${{ github.event.client_payload.repo }} + else + TESTS=all + KERNEL=5.19 + HOSTAPD_VERSION=09a281e52a25b5461c4b08d261f093181266a554 + ELL_REF="refs/heads/workflow" + REF="$GITHUB_REF" + REPO="$GITHUB_REPOSITORY" + fi + + # + # Now that the inputs are sorted, set the output of this step to these + # values so future jobs can refer to them. + # + echo "tests=$TESTS" >> $GITHUB_OUTPUT + echo "kernel=$KERNEL" >> $GITHUB_OUTPUT + echo "hostapd_version=$HOSTAPD_VERSION" >> $GITHUB_OUTPUT + echo "ell_ref=$ELL_REF" >> $GITHUB_OUTPUT + echo "repository=$REPO" >> $GITHUB_OUTPUT + echo "ref_branch=$REF" >> $GITHUB_OUTPUT + + - name: Cache UML Kernel + id: cache-uml-kernel + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }} + key: um-linux-${{ steps.inputs.outputs.kernel }}_ubuntu22 + + - name: Cache Hostapd + id: cache-hostapd + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }} + ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }} + key: hostapd_${{ steps.inputs.outputs.hostapd_version }}_ssl3 + + - name: Cache WpaSupplicant + id: cache-wpas + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }} + ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }} + key: wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }}_ssl3 + + - name: Checkout IWD + uses: actions/checkout@v3 + with: + path: iwd + repository: IWDTestBot/iwd + token: ${{ secrets.ACTION_TOKEN }} + + - name: Checkout ELL + uses: actions/checkout@v3 + with: + path: ell + repository: IWDTestBot/ell + ref: ${{ steps.inputs.outputs.ell_ref }} + + - name: Checkout CiBase + uses: actions/checkout@v3 + with: + repository: IWDTestBot/cibase + path: cibase + + - name: Checkout CI + uses: actions/checkout@v3 + with: + repository: IWDTestBot/iwd-ci + path: iwd-ci + + - name: Tar files + run: | + FILES="iwd ell cibase iwd-ci" + + if [ "${{ steps.cache-uml-kernel.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/um-linux-${{ steps.inputs.outputs.kernel }}" + fi + + if [ "${{ steps.cache-hostapd.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/hostapd_${{ steps.inputs.outputs.hostapd_version }}" + FILES+=" ${{ github.workspace }}/cache/hostapd_cli_${{ steps.inputs.outputs.hostapd_version }}" + fi + if [ "${{ steps.cache-wpas.outputs.cache-hit }}" == 'true' ] + then + FILES+=" ${{ github.workspace }}/cache/wpa_supplicant_${{ steps.inputs.outputs.hostapd_version }}" + FILES+=" ${{ github.workspace }}/cache/wpa_cli_${{ steps.inputs.outputs.hostapd_version }}" + fi + + tar -cvf archive.tar $FILES + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: iwd-artifacts + path: | + archive.tar + + iwd-alpine-ci: + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: iwd-artifacts + + - name: Untar + run: tar -xf archive.tar + + - name: Modprobe pkcs8_key_parser + run: | + sudo modprobe pkcs8_key_parser + + - name: Alpine CI + uses: IWDTestBot/iwd-ci@master + with: + ref_branch: ${{ needs.setup.outputs.ref_branch }} + repository: ${{ needs.setup.outputs.repository }} + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + ci: musl + + iwd-ci: + runs-on: ubuntu-22.04 + needs: setup + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: iwd-artifacts + + - name: Untar + run: tar -xf archive.tar + + - name: Cache UML Kernel + id: cache-uml-kernel + uses: actions/cache@v3 + with: + path: ${{ github.workspace }}/cache/um-linux-${{ needs.setup.outputs.kernel }} + key: um-linux-${{ needs.setup.outputs.kernel }}_ubuntu22 + + - name: Cache Hostapd + id: cache-hostapd + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/hostapd_${{ needs.setup.outputs.hostapd_version }} + ${{ github.workspace }}/cache/hostapd_cli_${{ needs.setup.outputs.hostapd_version }} + key: hostapd_${{ needs.setup.outputs.hostapd_version }}_ssl3 + + - name: Cache WpaSupplicant + id: cache-wpas + uses: actions/cache@v3 + with: + path: | + ${{ github.workspace }}/cache/wpa_supplicant_${{ needs.setup.outputs.hostapd_version }} + ${{ github.workspace }}/cache/wpa_cli_${{ needs.setup.outputs.hostapd_version }} + key: wpa_supplicant_${{ needs.setup.outputs.hostapd_version }}_ssl3 + + - name: Modprobe pkcs8_key_parser + run: | + sudo modprobe pkcs8_key_parser + echo ${{ needs.setup.outputs.ref_branch }} + echo ${{ needs.setup.outputs.repository }} + + - name: Run CI + uses: IWDTestBot/iwd-ci@master + with: + ref_branch: ${{ needs.setup.outputs.ref_branch }} + repository: ${{ needs.setup.outputs.repository }} + tests: ${{ needs.setup.outputs.tests }} + kernel: ${{ needs.setup.outputs.kernel }} + hostapd_version: ${{ needs.setup.outputs.hostapd_version }} + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + ci: main + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-runner-logs + path: ${{ github.workspace }}/log diff --git a/.github/workflows/pw-to-pr-email.txt b/.github/workflows/pw-to-pr-email.txt new file mode 100644 index 00000000..0ad6d765 --- /dev/null +++ b/.github/workflows/pw-to-pr-email.txt @@ -0,0 +1,16 @@ +This is an automated email and please do not reply to this email. + +Dear Submitter, + +Thank you for submitting the patches to the IWD mailing list. +While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository. + +----- Output ----- +{} + +Please resolve the issue and submit the patches again. + + +--- +Regards, +IWDTestBot diff --git a/.github/workflows/pw-to-pr.json b/.github/workflows/pw-to-pr.json new file mode 100644 index 00000000..b4491413 --- /dev/null +++ b/.github/workflows/pw-to-pr.json @@ -0,0 +1,14 @@ +{ + "email": { + "enable": true, + "server": "smtp.gmail.com", + "port": 587, + "user": "iwd.ci.bot@gmail.com", + "starttls": true, + "default-to": "prestwoj@gmail.com", + "only-maintainers": false, + "maintainers": [ + "prestwoj@gmail.com" + ] + } +} diff --git a/.github/workflows/schedule_work.yml b/.github/workflows/schedule_work.yml new file mode 100644 index 00000000..cfc14fba --- /dev/null +++ b/.github/workflows/schedule_work.yml @@ -0,0 +1,43 @@ +name: Sync Upstream +on: + schedule: + - cron: "*/15 * * * *" + workflow_dispatch: + +jobs: + repo-sync: + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v2 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Manage Repo + uses: IWDTestBot/action-manage-repo@master + with: + src_repo: "https://git.kernel.org/pub/scm/network/wireless/iwd.git" + src_branch: "master" + dest_branch: "master" + workflow_branch: "workflow" + github_token: ${{ secrets.GITHUB_TOKEN }} + + create_pr: + needs: repo-sync + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Patchwork to PR + uses: IWDTestBot/action-patchwork-to-pr@master + with: + pw_key_str: "user" + github_token: ${{ secrets.ACTION_TOKEN }} + email_token: ${{ secrets.EMAIL_TOKEN }} + patchwork_token: ${{ secrets.PATCHWORK_TOKEN }} + config: https://raw.githubusercontent.com/IWDTestBot/iwd/workflow/.github/workflows/pw-to-pr.json + patchwork_id: "408" + email_message: https://raw.githubusercontent.com/IWDTestBot/iwd/workflow/.github/workflows/pw-to-pr-email.txt diff --git a/src/scan.c b/src/scan.c index aeab6516..f4c2e548 100644 --- a/src/scan.c +++ b/src/scan.c @@ -62,6 +62,7 @@ static uint32_t SCAN_MAX_INTERVAL; static uint32_t SCAN_INIT_INTERVAL; static struct l_queue *scan_contexts; +static struct l_hashmap *scan_freq_map; static struct l_genl_family *nl80211; @@ -2316,6 +2317,37 @@ static void scan_retry_pending(uint32_t wiphy_id) } } +static void scan_update_freq_map_entry(uint32_t freq, void *user_data) +{ + void *existing = l_hashmap_lookup(scan_freq_map, L_UINT_TO_PTR(freq)); + uint64_t now = l_time_now(); + + if (existing) { + l_hashmap_remove(scan_freq_map, L_UINT_TO_PTR(freq)); + } + + l_hashmap_insert(scan_freq_map, L_UINT_TO_PTR(freq), L_UINT_TO_PTR(now)); +} + +static void scan_update_freq_map(struct scan_freq_set *freqs) +{ + scan_freq_set_foreach(freqs, scan_update_freq_map_entry, NULL); +} + +uint64_t scan_get_freq_age(uint32_t freq) +{ + void *entry = l_hashmap_lookup(scan_freq_map, L_UINT_TO_PTR(freq)); + + if (entry) { + uint64_t timestamp = (uintptr_t) entry; + uint64_t now = l_time_now(); + + return (now - timestamp) / 1000000; + } + + return UINT64_MAX; +} + static void scan_notify(struct l_genl_msg *msg, void *user_data) { struct l_genl_attr attr; @@ -2461,6 +2493,8 @@ static void scan_notify(struct l_genl_msg *msg, void *user_data) scan_get_results(sc, sr, freqs); + scan_update_freq_map(freqs); + break; } @@ -2645,6 +2679,7 @@ static int scan_init(void) const struct l_settings *config = iwd_get_config(); scan_contexts = l_queue_new(); + scan_freq_map = l_hashmap_new(); RANK_2G_FACTOR = scan_get_band_rank_modifier(BAND_FREQ_2_4_GHZ); RANK_5G_FACTOR = scan_get_band_rank_modifier(BAND_FREQ_5_GHZ); @@ -2688,6 +2723,7 @@ static void scan_exit(void) scan_contexts = NULL; l_genl_family_free(nl80211); nl80211 = NULL; + l_hashmap_destroy(scan_freq_map, NULL); } IWD_MODULE(scan, scan_init, scan_exit) diff --git a/src/scan.h b/src/scan.h index 4c1ebc21..135ffa5e 100644 --- a/src/scan.h +++ b/src/scan.h @@ -182,3 +182,5 @@ double scan_get_band_rank_modifier(enum band_freq band); bool scan_wdev_add(uint64_t wdev_id); bool scan_wdev_remove(uint64_t wdev_id); + +uint64_t scan_get_freq_age(uint32_t freq); diff --git a/src/station.c b/src/station.c index 9972ea76..87cf9df0 100644 --- a/src/station.c +++ b/src/station.c @@ -67,6 +67,8 @@ #define STATION_RECENT_NETWORK_LIMIT 5 #define STATION_RECENT_FREQS_LIMIT 5 +#define STATION_MAX_SCAN_FREQ_AGE 3 +#define STATION_MAX_SCAN_FREQS 10 static struct l_queue *station_list; static uint32_t netdev_watch; @@ -124,7 +126,7 @@ struct station { struct l_queue *roam_bss_list; /* Frequencies split into subsets by priority */ - struct scan_freq_set *scan_freqs_order[3]; + struct scan_freq_set *scan_freqs_order[4]; unsigned int dbus_scan_subset_idx; uint32_t wiphy_watch; @@ -2385,6 +2387,8 @@ static void station_roam_retry(struct station *station) station_roam_timeout_rearm(station, roam_retry_interval); } +static void station_start_roam(struct station *station); + static void station_roam_failed(struct station *station) { l_debug("%u", netdev_get_ifindex(station->netdev)); @@ -2414,10 +2418,9 @@ static void station_roam_failed(struct station *station) goto delayed_retry; /* - * If we tried a limited scan, failed and the signal is still low, - * repeat with a full scan right away + * If the signal is still low, keep trying to roam */ - if (station->signal_low && !station->roam_scan_full) { + if (station->signal_low) { /* * Since we're re-using roam_scan_id, explicitly cancel * the scan here, so that the destroy callback is not called @@ -2426,8 +2429,8 @@ static void station_roam_failed(struct station *station) scan_cancel(netdev_get_wdev_id(station->netdev), station->roam_scan_id); - if (!station_roam_scan(station, NULL)) - return; + station_start_roam(station); + return; } delayed_retry: @@ -3102,12 +3105,85 @@ static void station_neighbor_report_cb(struct netdev *netdev, int err, station_roam_failed(station); } +static void station_filter_roam_scan_freq(uint32_t freq, void *user_data) +{ + struct scan_freq_set *freqs = user_data; + uint64_t age = scan_get_freq_age(freq); + + if (scan_freq_set_size(freqs) >= STATION_MAX_SCAN_FREQS) { + return; + } + + if (age < STATION_MAX_SCAN_FREQ_AGE) { + return; + } + + scan_freq_set_add(freqs, freq); +} + +static struct scan_freq_set *station_get_roam_scan_freqs(struct station *station) +{ + struct scan_freq_set *tmp; + struct scan_freq_set *scan_freqs; + + scan_freqs = scan_freq_set_new(); + + /* Add current frequency, always scan this to get updated data for the + * current BSS */ + scan_freq_set_add(scan_freqs, station->connected_bss->frequency); + + /* Add neighbor frequencies */ + scan_freq_set_foreach(station->roam_freqs, station_filter_roam_scan_freq, scan_freqs); + if (scan_freq_set_size(scan_freqs) >= STATION_MAX_SCAN_FREQS) { + goto out; + } + + /* Add known frequencies */ + const struct network_info *info = network_get_info( + station->connected_network); + tmp = network_info_get_roam_frequencies(info, + station->connected_bss->frequency, + 10); + scan_freq_set_foreach(tmp, station_filter_roam_scan_freq, scan_freqs); + scan_freq_set_free(tmp); + if (scan_freq_set_size(scan_freqs) >= STATION_MAX_SCAN_FREQS) { + goto out; + } + + /* Add frequencies based on the prioritized subsets */ + for (uint8_t i = 0; i < L_ARRAY_SIZE(station->scan_freqs_order); i++) { + scan_freq_set_foreach(station->scan_freqs_order[i], station_filter_roam_scan_freq, scan_freqs); + if (scan_freq_set_size(scan_freqs) >= STATION_MAX_SCAN_FREQS) { + goto out; + } + } + +out: + /* TODO: Arbitrary number to not have too small freq list */ + if (scan_freq_set_size(scan_freqs) <= 5) { + /* Might as well add the neighbors */ + scan_freq_set_merge(scan_freqs, station->roam_freqs); + } + + return scan_freqs; +} + static void station_start_roam(struct station *station) { int r; + struct scan_freq_set *freqs; station->preparing_roam = true; + /* TODO: Need to request neighbor report here, like below */ + + freqs = station_get_roam_scan_freqs(station); + station_roam_scan(station, freqs); + + scan_freq_set_free(freqs); + + return; + /* * If current BSS supports Neighbor Reports, narrow the scan down * to channels occupied by known neighbors in the ESS. If no neighbor @@ -5007,44 +5083,79 @@ static void station_add_2_4ghz_freq(uint32_t freq, void *user_data) static void station_fill_scan_freq_subsets(struct station *station) { - const struct scan_freq_set *supported = - wiphy_get_supported_freqs(station->wiphy); unsigned int subset_idx = 0; - /* - * Scan the 2.4GHz "social channels" first, 5GHz second, if supported, - * all other 2.4GHz channels last. To be refined as needed. - */ + station->scan_freqs_order[subset_idx] = scan_freq_set_new(); + + /* Subset 0: 2.4GHz "social channels" and lower 5GHz non-DFS channels */ if (allowed_bands & BAND_FREQ_2_4_GHZ) { - station->scan_freqs_order[subset_idx] = scan_freq_set_new(); - scan_freq_set_add(station->scan_freqs_order[subset_idx], 2412); - scan_freq_set_add(station->scan_freqs_order[subset_idx], 2437); - scan_freq_set_add(station->scan_freqs_order[subset_idx], 2462); - subset_idx++; + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2412); /* 1 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2437); /* 6 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2462); /* 11 */ } - /* - * TODO: It may might sense to split up 5 and 6ghz into separate subsets - * since the channel set is so large. - */ - if (allowed_bands & (BAND_FREQ_5_GHZ | BAND_FREQ_6_GHZ)) { - uint32_t mask = allowed_bands & - (BAND_FREQ_5_GHZ | BAND_FREQ_6_GHZ); - struct scan_freq_set *set = scan_freq_set_clone(supported, - mask); - - /* 5/6ghz didn't add any frequencies */ - if (scan_freq_set_isempty(set)) { - scan_freq_set_free(set); - } else - station->scan_freqs_order[subset_idx++] = set; + if (allowed_bands & BAND_FREQ_5_GHZ) { + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5180); /* 36 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5200); /* 40 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5220); /* 44 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5240); /* 48 */ } - /* Add remaining 2.4ghz channels to subset */ + station->scan_freqs_order[++subset_idx] = scan_freq_set_new(); + + /* Subset 1: 2.4GHz common "middle channels" and high 5GHz non-DFS channels */ if (allowed_bands & BAND_FREQ_2_4_GHZ) { - station->scan_freqs_order[subset_idx] = scan_freq_set_new(); - scan_freq_set_foreach(supported, station_add_2_4ghz_freq, - station->scan_freqs_order[subset_idx]); + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2422); /* 3 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2427); /* 4 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2447); /* 8 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2452); /* 9 */ + } + + if (allowed_bands & BAND_FREQ_5_GHZ) { + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5745); /* 149 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5765); /* 153 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5785); /* 157 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5805); /* 161 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5825); /* 165 */ + } + + station->scan_freqs_order[++subset_idx] = scan_freq_set_new(); + + /* TODO: Add 6GHz here, after more common 2.4 and 5GHz, but before DFS */ + + /* Subset 2: 2.4GHz remaining channels and 5GHz most common DFS channels */ + if (allowed_bands & BAND_FREQ_2_4_GHZ) { + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2417); /* 2 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2432); /* 5 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2442); /* 7 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 2457); /* 10 */ + } + + if (allowed_bands & BAND_FREQ_5_GHZ) { + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5260); /* 52 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5280); /* 56 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5300); /* 60 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5320); /* 64 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5500); /* 100 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5520); /* 104 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5540); /* 108 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5560); /* 112 */ + } + + station->scan_freqs_order[++subset_idx] = scan_freq_set_new(); + + /* Subset 3: Remaining 5GHz DFS channels */ + if (allowed_bands & BAND_FREQ_5_GHZ) { + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5340); /* 68 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5480); /* 96 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5580); /* 116 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5600); /* 120 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5620); /* 124 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5640); /* 128 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5660); /* 132 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5680); /* 136 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5700); /* 140 */ + scan_freq_set_add(station->scan_freqs_order[subset_idx], 5720); /* 144 */ } /* @@ -5223,11 +5334,8 @@ static void station_free(struct station *station) l_queue_destroy(station->anqp_pending, remove_anqp); - scan_freq_set_free(station->scan_freqs_order[0]); - scan_freq_set_free(station->scan_freqs_order[1]); - - if (station->scan_freqs_order[2]) - scan_freq_set_free(station->scan_freqs_order[2]); + for (uint8_t i = 0; i < 4; i++) + scan_freq_set_free(station->scan_freqs_order[i]); wiphy_state_watch_remove(station->wiphy, station->wiphy_watch); diff --git a/src/util.c b/src/util.c index 65b97c8e..1e1dfc15 100644 --- a/src/util.c +++ b/src/util.c @@ -637,6 +637,17 @@ struct scan_freq_set *scan_freq_set_clone(const struct scan_freq_set *set, return new; } +uint32_t scan_freq_set_size(struct scan_freq_set *freqs) +{ + uint32_t size = 0; + + size += __builtin_popcount(freqs->channels_2ghz); + size += l_uintset_size(freqs->channels_5ghz); + size += l_uintset_size(freqs->channels_6ghz); + + return size; +} + /* First 64 entries calculated by 1 / pow(n, 0.3) for n >= 1 */ static const double rankmod_table[] = { 1.0000000000, 0.8122523964, 0.7192230933, 0.6597539554, diff --git a/src/util.h b/src/util.h index 8aef2985..7c024c79 100644 --- a/src/util.h +++ b/src/util.h @@ -138,6 +138,7 @@ uint32_t *scan_freq_set_to_fixed_array(const struct scan_freq_set *set, size_t *len_out); struct scan_freq_set *scan_freq_set_clone(const struct scan_freq_set *set, uint32_t band_mask); +uint32_t scan_freq_set_size(struct scan_freq_set *freqs); DEFINE_CLEANUP_FUNC(scan_freq_set_free);