. "$BST_LIB" # BST-TIMEOUT: 900 # ~45 cases, and the cost is EXECS: six fresh wasm module # # instantiations of /usr/sbin/hostapd, which is 36.4 MB -- # # by some way the largest exec this suite family stages -- # # plus five of hostapd_cli at 307 KB. Predicted ~240 s; NOT # # MEASURED ON TARGET YET. This port's first on-target run is # # the batch verify, and the measured elapsed goes in the # # test plan rather than in this comment, which would cost an # # image build to keep the shipped suite byte-identical. # # hostapd 2.10 (meta-openembedded meta-oe/recipes-connectivity/hostapd_2.10.bb, # `inherit update-rc.d systemd pkgconfig features_check', DEPENDS = libnl # openssl, oe_runmake install, and NO meta-brintos bbappend and no patch) on the # wasm32-hwjs glibc image -- the user-space daemon for IEEE 802.11 AP management # and the IEEE 802.1X/WPA/EAP/RADIUS authenticator. Two programs ship, both in # /usr/sbin: hostapd itself and hostapd_cli, the client that drives a running # daemon over its AF_UNIX control interface. # # ============================================================================ # THERE IS NO WIRELESS DEVICE BEHIND THIS MACHINE, AND THAT IS THE SUBJECT. # ============================================================================ # # arch/wasm32/configs/wasm32_defconfig sets CONFIG_NET=y, CONFIG_INET=y and # CONFIG_UNIX=y and nothing else on the networking side -- no CONFIG_CFG80211, # no CONFIG_MAC80211, and CONFIG_PACKET unset. So net/wireless is not compiled, # the `nl80211' generic-netlink family is never registered, /sys/class/ieee80211 # does not exist, and there is no AF_PACKET to put a management frame on even if # there were a radio. Every case below is written against that absence rather # than around it: REPORTING IT DETERMINISTICALLY, AND EXITING, is the answer # this port is expected to give, and asserting it is what turns "we could not # test this" into a regression signal. # # GENERIC NETLINK ITSELF IS EXPECTED TO BE PRESENT, which is what makes the # absence legible rather than indistinguishable from a broken port. # net/netlink/{af_netlink,genetlink}.o are obj-y under CONFIG_NET, and # 79-libsocketcan.test already measures a real rtnetlink round trip on this # image, and 93-wpan-tools takes the same reading one family over. So hostapd is expected to get all the way to genl_ctrl_resolve(3) and # be told only that the family is missing. That is a PREDICTION about this image # and it is scored as one: `driver/depth' below names which of upstream's four # distinguishable failures it actually saw, so a wrong prediction reddens # exactly one case and reports what happened instead of reddening a port. # # The four depths, all MSG_ERROR and so all visible at the default log level: # # 1. "netlink: Failed to open netlink socket" -- AF_NETLINK absent # 2. "netlink: Failed to bind netlink socket" -- bound refused # 3. "nl80211: Failed to connect to generic netlink" -- genl_connect refused # 4. "nl80211: 'nl80211' generic netlink not found" -- EXPECTED: everything # reached, family absent # # Depth 4 is the one this machine should give. 1 and 2 would mean something much # worse about CONFIG_NET than a missing radio, and the suite distinguishes them # rather than scoring "it failed". # # ============================================================================ # EVERY EXPECTED STRING BELOW WAS READ OFF THE SHIPPED MODULES. # ============================================================================ # # The diagnostics, the usage banner and both version strings were confirmed with # strings(1) against the wasm32 /usr/sbin/hostapd and /usr/sbin/hostapd_cli this # package installs -- not read off the tarball and not guessed. The EXIT STATUSES # are read off upstream's source and are the part that is predicted: # # * `hostapd -v' and `hostapd -h' exit 1, NOT 0. show_version() writes to # STDERR and the -v arm is a hardcoded exit(1); usage() ends the same way. # Asserting rc 0 for -h is the reflex, and it reds against every build of # this package. # * `hostapd' with no configuration file is `optind == argc' -> usage(), so it # is the same rc 1 and the same banner. # * hostapd_cli's -h and -v arms `return 0', so THOSE two are rc 0. The two # programs disagree with each other, deliberately, and both are pinned. # * hostapd_cli with nothing to connect to `return -1' from main, which is # exit status 255. # # ============================================================================ # hostapd_cli IS NEVER RUN WITHOUT A COMMAND. THAT WOULD HANG THE SUITE. # ============================================================================ # # `interactive = (argc == optind) && (action_file == NULL)' -- so a BARE # hostapd_cli enters interactive mode, and interactive mode retries the control # socket in an unbounded `os_sleep(1, 0)' loop, printing "Could not connect to # hostapd - re-trying" exactly once and then never returning. That is upstream's # design, the ticket scopes this port to the command line, and this file passes # a command to every hostapd_cli invocation. It is called out here because the # obvious "just run it and see" is the one invocation that would wedge the guest. # # ============================================================================ # BOUNDING, AND WHY NOT timeout(1). # ============================================================================ # # timeout(1) can kill nothing this loop cannot (brintos/linux#21), and before # the brintos/linux#77 fix its timer never fired, which made it a second hang # rather than a bound. `hap_bounded' below is bst_probe's shape # (completion sentinel, /proc/uptime as the clock, `sleep 1' with builtins only # in the loop body) with the verdict left to the caller, because bst_probe # scores rc 0 as the pass and every hostapd invocation here is expected to exit # non-zero. The bound is a HANG DETECTOR, not a budget: every path below either # answers on the first syscall that fails or does not answer at all. # # ============================================================================ # WHAT IS EXERCISED FOR REAL: THE CONFIGURATION PARSER, WHICH IS NOT SMALL. # ============================================================================ # # hostapd_config_read() runs to completion BEFORE any socket is opened, so the # parser is ordinary userland C on this arm and is the one part of this package # that is genuinely covered here rather than gated. A valid fixture is asserted # to be ACCEPTED -- evidenced by the run reaching the driver diagnostic with no # "errors found in configuration file" line -- and a fixture with one unknown # key is asserted to be refused with upstream's message AND ITS LINE NUMBER, # which is the field a parser regression would move first. PATH="$PATH:/usr/sbin:/sbin" export PATH require hostapd hostapd/present W=${TMPDIR:-/tmp}/bst-hostapd.$$ mkdir -p "$W" || { bst_notok hostapd/workdir "cannot create $W"; exit 0; } HAP_BOUND=180 # per hostapd invocation. 36.4 MB is a large module to # instantiate and this is a loaded guest; the bound is set # to catch a daemon that STAYED RESIDENT, not to time one. CLI_BOUND=60 # hostapd_cli is 307 KB and answers on its first syscall. # hap_bounded -- run with stdout at $W/out, stderr at # $W/err and no result line of its own. Sets HAP_RC to the exit status, or 124 # when the bound expired (the child is killed). Keeping the two streams apart is # load-bearing here: wpa_printf() writes to STDOUT and show_version()/usage() # write to STDERR, and several cases below are about which of the two a line # came out of. hap_bounded() { _hb_bound=$1; shift rm -f "$W/out" "$W/err" "$W/rc" { "$@" >"$W/out" 2>"$W/err"; echo $? >"$W/rc"; } & _hb_pid=$! _hb_t0= # BST-REDIRECT-OK: /proc is a pseudo-filesystem, never the virtiofs root if [ -r /proc/uptime ] && read -r _hb_u _ < /proc/uptime; then _hb_t0=${_hb_u%.*}; fi _hb_ticks=0 while [ ! -e "$W/rc" ]; do _hb_d=$_hb_ticks # BST-REDIRECT-OK: /proc is a pseudo-filesystem, never the virtiofs root if [ -n "$_hb_t0" ] && read -r _hb_u _ < /proc/uptime; then _hb_d=$(( ${_hb_u%.*} - _hb_t0 )) fi if [ "$_hb_d" -ge "$_hb_bound" ]; then kill -9 "$_hb_pid" 2>/dev/null HAP_RC=124 return 124 fi sleep 1 _hb_ticks=$((_hb_ticks + 1)) done HAP_RC=0 # BST-REDIRECT-OK: $W is the suite's tmpfs workdir, never the rootfs [ -s "$W/rc" ] && read -r HAP_RC < "$W/rc" 2>/dev/null case "$HAP_RC" in ''|*[!0-9]*) HAP_RC=0 ;; esac return 0 } # hap_both -- stdout and stderr of the last hap_bounded run, joined. hap_both() { cat "$W/out" "$W/err" 2>/dev/null; } # hap_fail -- the one-shot form for the paths # that return before any socket is opened. They signal through the exit status # as much as through the text, which check_out cannot express (it requires # rc 0). hap_fail() { _hf_id=$1; _hf_want=$2; _hf_needle=$3; shift 3 _hf_out=$("$@" 2>&1); _hf_rc=$? case "$_hf_out" in *"$_hf_needle"*) _hf_hit=1 ;; *) _hf_hit=0 ;; esac if [ "$_hf_rc" -eq "$_hf_want" ] && [ "$_hf_hit" -eq 1 ]; then bst_ok "$_hf_id" elif bst_execfail "$_hf_out"; then bst_unrun "$_hf_id" "$_hf_out" else bst_notok "$_hf_id" "rc=$_hf_rc want=$_hf_want needle:'$_hf_needle' got:'$(_bst_1line "$_hf_out")'"; fi } # ------------------------------------------------------- what shipped -------- # Both programs are installed into ${sbindir} by the recipe's own do_install, so # they land in /usr/sbin and not /usr/bin. The paths are asserted directly: a # caller resolving them through a PATH without /usr/sbin finds nothing and reads # the port as ABSENT rather than broken, which is a failure that looks like # coverage. for b in hostapd hostapd_cli; do check_rc "hostapd/sbin-$b" 0 test -x "/usr/sbin/$b" check_rc "hostapd/not-in-bin-$b" 1 test -e "/usr/bin/$b" done # dpkg KNOWS the package -- every case above would read the same if some other # recipe had dropped these two names into /usr/sbin. sed -n '/^Package: hostapd$/,/^$/p' /var/lib/dpkg/status > "$W/st" 2>/dev/null check_out hostapd/pkg-installed "Status: install ok installed" cat "$W/st" check_out hostapd/pkg-version "Version: 2.10-r0" cat "$W/st" # The one runtime dependency this recipe's packaging resolves to on this distro. check_out hostapd/pkg-depends "brintos-libc-so" cat "$W/st" # The packaged file list, from dpkg's side. A .list names directories too and # without a trailing slash, so each name is matched whole. PKGLIST=/var/lib/dpkg/info/hostapd.list check_rc hostapd/pkg-list-present 0 test -s "$PKGLIST" check hostapd/pkg-list-sbin-hostapd grep -qx /usr/sbin/hostapd "$PKGLIST" check hostapd/pkg-list-sbin-hostapd_cli grep -qx /usr/sbin/hostapd_cli "$PKGLIST" check hostapd/pkg-list-conf grep -qx /etc/hostapd.conf "$PKGLIST" check hostapd/pkg-list-initscript grep -qx /etc/init.d/hostapd "$PKGLIST" # FOUR FILES AND NO MORE. The recipe's do_install also writes a systemd unit # into ${systemd_unitdir}/system, and this distro carries no "systemd" feature # -- so nothing packages it and it does not reach the image. Asserted as a # tripwire rather than left implicit: the day this distro grows systemd, this # case diverges and says where. check_rc hostapd/no-systemd-unit 1 test -e /lib/systemd/system/hostapd.service # The stock sample configuration ships as a CONFFILE and is 126 KB of commented # template -- it is documentation, not a runnable configuration, and nothing in # this suite uses it as one. Its presence is the packaging assertion; the # fixtures below are written fresh into tmpfs. check_rc hostapd/conf-shipped 0 test -s /etc/hostapd.conf check_out hostapd/conf-is-template "##### hostapd configuration file" \ head -c 4096 /etc/hostapd.conf # The sysvinit script the update-rc.d class packages. It is not RUN here: this # image boots no init system that would, and starting a daemon that cannot # initialise its driver is what the foreground cases below already measure. check_rc hostapd/initscript 0 test -x /etc/init.d/hostapd # hostapd links its crypto against openssl (CONFIG_EAP_TLS, CONFIG_WPS and # CONFIG_RADIUS_SERVER are all set in the recipe's defconfig), so the port rests # on BRINTOS-295 having shipped. Asserted here so that a red below cannot be # mistaken for a missing backend. check_rc hostapd/openssl-present 0 test -x /usr/bin/openssl # ------------------------------------------- the machine, stated as fact ----- # No CONFIG_CFG80211, so net/wireless never registers its class... check_rc hostapd/no-ieee80211-class 1 test -e /sys/class/ieee80211 # ...and there is no wireless device to report statistics for. check_rc hostapd/no-proc-wireless 1 test -e /proc/net/wireless # CONFIG_PACKET is unset, so AF_PACKET does not register and /proc/net/packet -- # which af_packet.c creates in its init -- does not exist. This is the data path # an AP would need after nl80211 had given it an interface. check_rc hostapd/no-af-packet 1 test -e /proc/net/packet # THE CONTROL FOR THE DRIVER'S RED: netlink itself IS registered. # net/netlink/af_netlink.c creates /proc/net/netlink in its init, so its # presence says AF_NETLINK exists and the driver's failure below is attributable # to the missing FAMILY rather than to a missing protocol family. check_rc hostapd/netlink-control 0 test -e /proc/net/netlink # `lo' is the only interface, and it is a loopback: /sys is the oracle, type 772 # is ARPHRD_LOOPBACK. An AP interface would be type 801 (ARPHRD_IEEE80211_RADIOTAP) # or 1 behind a wireless device, and there is neither. check_out hostapd/lo-is-loopback "772" cat /sys/class/net/lo/type check_rc hostapd/no-wlan0 1 test -e /sys/class/net/wlan0 # ------------------------------------------- the pre-socket userland --------- # hostapd parses its options before it opens anything, so these three cases # would read the same on a machine with a radio. show_version() and usage() both # write to STDERR and both arms end in exit(1) -- rc 0 is the reflex here and it # is wrong. hap_fail hostapd/version 1 "hostapd v2.10" hostapd -v hap_fail hostapd/usage 1 "usage: hostapd [-hdBKtv]" hostapd -h # -h prints the version banner first, which is what makes the two arms one code # path. Pinned separately so a change to either is attributable. hap_fail hostapd/usage-banner 1 "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator" \ hostapd -h # `optind == argc' with no -g and no -b is the third way into usage(): hostapd # with no configuration file is an error, not a default. hap_fail hostapd/no-config 1 "usage: hostapd [-hdBKtv]" hostapd # hostapd_cli's two informational arms `return 0'. The two programs disagree # about this and both are pinned. check_out hostapd/cli-version "hostapd_cli v2.10" hostapd_cli -v check_out hostapd/cli-usage "usage: hostapd_cli [-p]" hostapd_cli -h # ------------------------------------------- the configuration parser -------- # A minimal open network. Everything here is a documented key and the file is # written into tmpfs, so nothing about it depends on the rootfs. cat > "$W/good.conf" <<'EOF' interface=wlan0 driver=nl80211 ssid=brintos-hostapd-test hw_mode=g channel=1 EOF # The same file with ONE unknown key appended, on a known line number. cp "$W/good.conf" "$W/bad.conf" echo 'brintos_no_such_key=1' >> "$W/bad.conf" check_rc hostapd/fixture-good 0 test -s "$W/good.conf" check_rc hostapd/fixture-bad 0 test -s "$W/bad.conf" # ONE invocation, six cases. The unknown key is refused by # hostapd_config_fill(), the count is reported by hostapd_config_read(), and # hostapd_interface_init() then fails in main() -- three lines from three # different functions, and asserting all three is what says the refusal # propagated rather than being printed and ignored. hap_bounded "$HAP_BOUND" hostapd "$W/bad.conf" bad_out=$(hap_both) if [ "$HAP_RC" = 124 ]; then bst_notok hostapd/bad-conf-terminates \ "did not return within ${HAP_BOUND}s on a configuration file it should have refused outright" bst_notok hostapd/bad-conf-item "no output: the run did not terminate" bst_notok hostapd/bad-conf-line "no output: the run did not terminate" bst_notok hostapd/bad-conf-count "no output: the run did not terminate" bst_notok hostapd/bad-conf-iface "no output: the run did not terminate" bst_notok hostapd/bad-conf-status "no output: the run did not terminate" elif bst_execfail "$bad_out"; then for c in terminates item line count iface status; do bst_unrun "hostapd/bad-conf-$c" "$bad_out" done else bst_ok hostapd/bad-conf-terminates case "$bad_out" in *"unknown configuration item 'brintos_no_such_key'"*) bst_ok hostapd/bad-conf-item ;; *) bst_notok hostapd/bad-conf-item \ "not upstream's unknown-item diagnostic: '$(_bst_1line "$bad_out")'" ;; esac # The line number is the field a parser regression moves first: the key is on # line 6 of a six-line file, and nothing else in the file is refused. case "$bad_out" in *"Line 6: unknown configuration item"*) bst_ok hostapd/bad-conf-line ;; *) bst_notok hostapd/bad-conf-line \ "the unknown key is on line 6 and hostapd did not say so: '$(_bst_1line "$bad_out")'" ;; esac case "$bad_out" in *"1 errors found in configuration file"*) bst_ok hostapd/bad-conf-count ;; *) bst_notok hostapd/bad-conf-count \ "want exactly one counted error: '$(_bst_1line "$bad_out")'" ;; esac case "$bad_out" in *"Failed to initialize interface"*) bst_ok hostapd/bad-conf-iface ;; *) bst_notok hostapd/bad-conf-iface \ "the parse error did not propagate out of hostapd_interface_init: '$(_bst_1line "$bad_out")'" ;; esac # A refused configuration must never reach the driver -- if it does, the # parser's verdict is decorative. case "$bad_out" in *"nl80211"*) bst_notok hostapd/bad-conf-status \ "a refused configuration still reached the nl80211 driver: '$(_bst_1line "$bad_out")'" ;; *) if [ "$HAP_RC" = 1 ]; then bst_ok hostapd/bad-conf-status else bst_notok hostapd/bad-conf-status "rc=$HAP_RC want=1"; fi ;; esac fi # ------------------------------------------- the driver, which is absent ----- # ONE invocation of the VALID fixture, and it carries the whole of this port's # subject: the configuration is accepted, the nl80211 driver cannot be # initialised for `wlan0', hostapd says so at a nameable depth, and it EXITS # rather than staying resident. hap_bounded "$HAP_BOUND" hostapd "$W/good.conf" good_out=$(hap_both) good_rc=$HAP_RC if [ "$good_rc" = 124 ]; then bst_notok hostapd/driver-terminates \ "STAYED RESIDENT for ${HAP_BOUND}s on a machine with no nl80211 -- it must report and exit, never block" for c in conf-accepted depth init-failed on-stdout status; do bst_notok "hostapd/driver-$c" "no verdict: the run did not terminate" done elif bst_execfail "$good_out"; then for c in terminates conf-accepted depth init-failed on-stdout status; do bst_unrun "hostapd/driver-$c" "$good_out" done else bst_ok hostapd/driver-terminates # THE PARSER ACCEPTED IT. Evidenced by the absence of the counted-errors line # and by the run having got as far as the driver at all -- an asserted # ABSENCE alone would also pass on a run that died before it could print. case "$good_out" in *"errors found in configuration file"*) bst_notok hostapd/driver-conf-accepted \ "the valid fixture was refused: '$(_bst_1line "$good_out")'" ;; *"nl80211"*|*"netlink"*) bst_ok hostapd/driver-conf-accepted ;; *) bst_notok hostapd/driver-conf-accepted \ "no parse error, but the run never reached the driver either: '$(_bst_1line "$good_out")'" ;; esac # WHICH OF UPSTREAM'S FOUR FAILURES THIS MACHINE GAVE. Depth 4 is the # prediction; the other three are named rather than scored as "it failed". case "$good_out" in *"'nl80211' generic netlink not found"*) hap_depth=family-absent ;; *"Failed to connect to generic netlink"*) hap_depth=genl-connect ;; *"netlink: Failed to bind netlink socket"*) hap_depth=netlink-bind ;; *"netlink: Failed to open netlink socket"*) hap_depth=netlink-open ;; *) hap_depth= ;; esac case "$hap_depth" in family-absent) bst_ok hostapd/driver-depth ;; genl-connect|netlink-bind|netlink-open) bst_notok hostapd/driver-depth \ "stopped at $hap_depth, not at the nl80211 family -- generic netlink is less available on this image than /proc/net/netlink says" ;; *) bst_notok hostapd/driver-depth \ "no recognised nl80211/netlink diagnostic: '$(_bst_1line "$good_out")'" ;; esac # main() must report the driver as the thing that failed, naming it. case "$good_out" in *"Failed to initialize driver 'nl80211'"*) bst_ok hostapd/driver-init-failed ;; *) bst_notok hostapd/driver-init-failed \ "hostapd_driver_init did not report the named driver: '$(_bst_1line "$good_out")'" ;; esac # wpa_printf() writes to STDOUT when there is no log file and no syslog -- # this image ships no syslogd, so the diagnostic is expected on stdout and NOT # on stderr. A port whose errors went to stderr would still "work" and would # break every consumer that reads hostapd's log the documented way. if grep -q "nl80211" "$W/out" 2>/dev/null; then bst_ok hostapd/driver-on-stdout elif grep -q "nl80211" "$W/err" 2>/dev/null; then bst_notok hostapd/driver-on-stdout "the driver diagnostic came out on STDERR; wpa_printf writes to stdout here" else bst_notok hostapd/driver-on-stdout "no nl80211 diagnostic on either stream" fi # ret is initialised to 1 and the driver failure goes to `out' without # clearing it, so the documented status for this path is 1. if [ "$good_rc" = 1 ]; then bst_ok hostapd/driver-status else bst_notok hostapd/driver-status "rc=$good_rc want=1 (main's ret is 1 on the out: path)"; fi fi # -t adds a ".: " prefix to every wpa_printf line, on the same stream. # It is the one logging option this defconfig leaves reachable without -d # (CONFIG_DEBUG_FILE and CONFIG_DEBUG_SYSLOG are both off), and it is asserted on # STDOUT specifically. hap_bounded "$HAP_BOUND" hostapd -t "$W/good.conf" ts_out=$(cat "$W/out" 2>/dev/null) if [ "$HAP_RC" = 124 ]; then bst_notok hostapd/timestamps "-t did not return within ${HAP_BOUND}s" elif bst_execfail "$(hap_both)"; then bst_unrun hostapd/timestamps "$(hap_both)" elif printf '%s\n' "$ts_out" | grep -q '^[0-9][0-9]*\.[0-9][0-9][0-9][0-9][0-9][0-9]: '; then bst_ok hostapd/timestamps else bst_notok hostapd/timestamps \ "no '.: ' prefix on stdout under -t: '$(_bst_1line "$ts_out")'" fi # ------------------------------------------- hostapd_cli, with no daemon ----- # ALWAYS with a command: a bare hostapd_cli is interactive and never returns # (see the header). `ping' is the cheapest command in the table. # # Two depths, and they are different questions. With the stock control directory # -- /var/run/hostapd, which this package does not create -- hostapd_cli stops at # its own access(2) on the CLIENT socket directory and perrors that path before # it ever builds a socket. Given a directory that exists, it gets past that and # fails at wpa_ctrl_open2() instead. Both end at main's # `perror("Failed to connect to hostapd - wpa_ctrl_open")' and `return -1', which # is exit status 255. hap_bounded "$CLI_BOUND" hostapd_cli -i wlan0 ping cli_out=$(hap_both) if [ "$HAP_RC" = 124 ]; then bst_notok hostapd/cli-no-daemon "blocked for ${CLI_BOUND}s instead of reporting the absent control interface" bst_notok hostapd/cli-no-daemon-status "no status: the run did not terminate" elif bst_execfail "$cli_out"; then bst_unrun hostapd/cli-no-daemon "$cli_out" bst_unrun hostapd/cli-no-daemon-status "$cli_out" else case "$cli_out" in *"Failed to connect to hostapd - wpa_ctrl_open"*) bst_ok hostapd/cli-no-daemon ;; *) bst_notok hostapd/cli-no-daemon \ "not upstream's wpa_ctrl_open diagnostic: '$(_bst_1line "$cli_out")'" ;; esac if [ "$HAP_RC" = 255 ]; then bst_ok hostapd/cli-no-daemon-status else bst_notok hostapd/cli-no-daemon-status "rc=$HAP_RC want=255 (main returns -1)"; fi fi # The deeper depth: a control directory that EXISTS, on tmpfs, holding no # socket. access(2) succeeds, so the client socket is built and bound and only # the peer is missing -- which is what says AF_UNIX itself is sound here and the # case above is about an absent daemon rather than an absent socket layer. mkdir -p "$W/ctrl" hap_bounded "$CLI_BOUND" hostapd_cli -p "$W/ctrl" -s "$W/ctrl" -i wlan0 ping deep_out=$(hap_both) if [ "$HAP_RC" = 124 ]; then bst_notok hostapd/cli-ctrl-depth "blocked for ${CLI_BOUND}s against an empty control directory" elif bst_execfail "$deep_out"; then bst_unrun hostapd/cli-ctrl-depth "$deep_out" else case "$deep_out" in *"$W/ctrl: "*) bst_notok hostapd/cli-ctrl-depth \ "still stopped at access(2) on a directory that exists: '$(_bst_1line "$deep_out")'" ;; *"Failed to connect to hostapd - wpa_ctrl_open"*) if [ "$HAP_RC" = 255 ]; then bst_ok hostapd/cli-ctrl-depth else bst_notok hostapd/cli-ctrl-depth "reached wpa_ctrl_open but rc=$HAP_RC, want 255"; fi ;; *) bst_notok hostapd/cli-ctrl-depth \ "no wpa_ctrl_open diagnostic: '$(_bst_1line "$deep_out")'" ;; esac fi rm -rf "$W" 2>/dev/null