git: 643d6dce6c1e - main - tools/net80211: add mlme_assoc
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 01 Dec 2023 01:48:48 UTC
The branch main has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=643d6dce6c1e39f067f8d0feea8615913b324891 commit 643d6dce6c1e39f067f8d0feea8615913b324891 Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2023-12-01 01:37:25 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2023-12-01 01:48:34 +0000 tools/net80211: add mlme_assoc mlme_assoc is a tool to trigger net80211::ieee80211_sta_join1() calls which in certain conditions cause problems to the LinuxKPI 802.11 compat code (but also believed to possibly cause problems in case of race to other firmware based drivers). This has proven to be a good reproducer for the problem even on setups which otherwise could run for days without hitting it. Sponsored by: The FreeBSD Foundation PR: 271979 --- tools/tools/net80211/mlme_assoc/Makefile | 7 + tools/tools/net80211/mlme_assoc/README | 51 +++++++ tools/tools/net80211/mlme_assoc/mlme_assoc.c | 200 +++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) diff --git a/tools/tools/net80211/mlme_assoc/Makefile b/tools/tools/net80211/mlme_assoc/Makefile new file mode 100644 index 000000000000..580fb045ac52 --- /dev/null +++ b/tools/tools/net80211/mlme_assoc/Makefile @@ -0,0 +1,7 @@ +PROG= mlme_assoc +BINDIR= /usr/bin +MAN= + +SRCS= mlme_assoc.c + +.include <bsd.prog.mk> diff --git a/tools/tools/net80211/mlme_assoc/README b/tools/tools/net80211/mlme_assoc/README new file mode 100644 index 000000000000..fc5e754a58d6 --- /dev/null +++ b/tools/tools/net80211/mlme_assoc/README @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2023 The FreeBSD Foundation +# +# This documentation was written by Björn Zeeb under sponsorship from +# the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +This is a simple program to drive net80211::ieee80211_sta_join1() calls from +user space. + +The program optionally accepts an interface name (e.g., wlan42), or an +interface name, an SSID and a BSSID. + +In the former case of no SSID/BSSID passed it will query the scan results and +then try to join each entry from the scan with a short delay. + +In the lastter case giving the SSID/BSSID one can trigger the "canreassoc" case +in ieee80211_sta_join1() or not depending on whether one passes the currently +associated SSID/BSSID or not. + +The tool is useful to trigger net80211::newstate() changes while other +newstate() changes are pending or being executed. + +I was specifically developed to show a problem with the LinuxKPI 802.11 compat +code. The reason is that ieee80211_sta_join1() also calls in (*iv_update_bss)() +swapping nodes before initiating the state changes and in LinuxKPI state is on +the sta and not the vif causing all kinds of troubles, especially if we lose +a state transition before the taskq is run or if the iv_bss node gets swapped +before a task is executed. diff --git a/tools/tools/net80211/mlme_assoc/mlme_assoc.c b/tools/tools/net80211/mlme_assoc/mlme_assoc.c new file mode 100644 index 000000000000..c26aaa03fe87 --- /dev/null +++ b/tools/tools/net80211/mlme_assoc/mlme_assoc.c @@ -0,0 +1,200 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software was developed by Björn Zeeb under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * First get scan results in a hurry. + * Pick a random BSSID and try to assoc. + * Hopefully this is enough to trigger the newstate race along with the + * (*iv_update_bss)() logic. + * + * Alternatively pass IF SSID BSSID in and just try that. + */ + +#include <err.h> +#include <stdio.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <sys/ioctl.h> + +#include <net/if.h> +#include <net/ethernet.h> + +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_ioctl.h> + +static int +if_up(int sd, const char *ifnam) +{ + struct ifreq ifr; + int error; + + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name)); + + error = ioctl(sd, SIOCGIFFLAGS, &ifr); + if (error == -1) { + warn("SIOCGIFFLAGS"); + return (error); + } + + if (ifr.ifr_flags & IFF_UP) + return (0); + + ifr.ifr_flags |= IFF_UP; + + error = ioctl(sd, SIOCSIFFLAGS, &ifr); + if (error == -1) { + warn("SIOCSIFFLAGS"); + return (error); + } + + return (0); +} + +static int +try_mlme_assoc(int sd, const char *ifnam, uint8_t *ssid, uint8_t ssid_len, uint8_t *bssid) +{ + struct ieee80211req ireq; + struct ieee80211req_mlme mlme; + int error; + + memset(&mlme, 0, sizeof(mlme)); + mlme.im_op = IEEE80211_MLME_ASSOC; + if (ssid != NULL) + memcpy(mlme.im_ssid, ssid, ssid_len); + mlme.im_ssid_len = ssid_len; + if (bssid != NULL) + memcpy(mlme.im_macaddr, bssid, IEEE80211_ADDR_LEN); + + memset(&ireq, 0, sizeof(ireq)); + strlcpy(ireq.i_name, ifnam, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_MLME; + ireq.i_val = 0; + ireq.i_data = (void *)&mlme; + ireq.i_len = sizeof(mlme); + + error = ioctl(sd, SIOCS80211, &ireq); + if (error == -1) { + warn("SIOCS80211, %#x", ireq.i_type); + return (error); + } + + return (0); +} + +static int +mlme_assoc_scan_results(int sd, const char *ifnam) +{ + struct ieee80211req ireq; + struct ieee80211req_scan_result *sr; + uint8_t buf[32 * 1024], *p; + ssize_t len; + int error; + + memset(&ireq, 0, sizeof(ireq)); + strlcpy(ireq.i_name, ifnam, sizeof(ireq.i_name)); + ireq.i_type = IEEE80211_IOC_SCAN_RESULTS; + ireq.i_data = (void *)buf; + ireq.i_len = sizeof(buf); + + error = ioctl(sd, SIOCG80211, &ireq); + if (error == -1 || ireq.i_len < 0) { + warn("SIOCG80211, %#x", ireq.i_type); + return (error); + } + + p = buf; + len = ireq.i_len; + while (len > (ssize_t)sizeof(*sr)) { + sr = (struct ieee80211req_scan_result *)(void *)p; + p += sr->isr_len; + len -= sr->isr_len; + + error = try_mlme_assoc(sd, ifnam, (void *)(sr + 1), sr->isr_ssid_len, + sr->isr_bssid); + if (error != 0) { + warnx("try_mlme_assoc"); + return (error); + } + + usleep(100000); + } + + return (0); +} + +int +main(int argc, char *argv[]) +{ + const char *ifnam; + uint8_t *ssid, *bssid; + struct ether_addr ea; + int error, sd; + + ifnam = "wlan0"; + ssid = NULL; + bssid = NULL; + + if (argc == 4) { + ifnam = argv[1]; + ssid = (uint8_t *)argv[2]; + bssid = (uint8_t *)ether_aton_r(argv[3], &ea); + if (bssid == NULL) + warnx("ether_aton_r, ignoring BSSID"); + } else if (argc == 2) { + ifnam = argv[1]; + } + + sd = socket(AF_LOCAL, SOCK_DGRAM, 0); + if (sd == -1) + errx(EX_UNAVAILABLE, "socket"); + + error = if_up(sd, ifnam); + if (error != 0) + errx(EX_UNAVAILABLE, "if_up"); + + if (argc == 4) { + error = try_mlme_assoc(sd, ifnam, ssid, strlen((const char *)ssid), bssid); + if (error != 0) + errx(EX_UNAVAILABLE, "try_mlme_assoc"); + + } else { + error = mlme_assoc_scan_results(sd, ifnam); + if (error != 0) + errx(EX_UNAVAILABLE, "mlme_assoc_scan_results"); + } + + close(sd); + + return (0); +}