1#!/bin/bash 2# 3# Copyright (c) 2018, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30set -e 31set -x 32 33die() 34{ 35 echo " *** ERROR: " "$*" 36 exit 1 37} 38 39at_exit() 40{ 41 EXIT_CODE=$? 42 43 sudo killall expect || true 44 sudo killall ot-ctl || true 45 sudo killall ot-daemon || true 46 sudo killall ot-cli || true 47 sudo killall ot-rcp || true 48 sudo killall socat || true 49 50 exit $EXIT_CODE 51} 52 53wait_for_socat() 54{ 55 if [[ "$(head -n2 "$SOCAT_OUTPUT" | wc -l | tr -d ' ')" == 2 ]]; then 56 RADIO_PTY=$(head -n1 "$SOCAT_OUTPUT" | grep -o '/dev/.\+') 57 CORE_PTY=$(head -n2 "$SOCAT_OUTPUT" | tail -n1 | grep -o '/dev/.\+') 58 return 0 59 else 60 echo 'Still waiting for socat' 61 fi 62 return 1 63} 64 65wait_for_leader() 66{ 67 if grep -q leader "$OT_OUTPUT"; then 68 return 0 69 else 70 echo 'Still waiting for leader' 71 fi 72 return 1 73} 74 75timeout_run() 76{ 77 local count="$1" 78 local exit_code 79 shift 1 80 81 while [[ $count != 0 && $exit_code != 0 ]]; do 82 count=$((count - 1)) 83 "$@" && return 0 || exit_code=$? 84 sleep 1 85 done 86 87 return $exit_code 88} 89 90do_build() 91{ 92 ./script/cmake-build simulation 93 ./script/cmake-build posix -DOT_PLATFORM_NETIF=1 -DOT_PLATFORM_UDP=1 -DOT_UDP_FORWARD=0 -DOT_POSIX_MAX_POWER_TABLE=1 -DOT_DAEMON="${OT_DAEMON}" -DOT_READLINE="${OT_READLINE}" 94} 95 96do_check() 97{ 98 trap at_exit INT TERM EXIT 99 100 sudo rm -rf tmp 101 102 SOCAT_OUTPUT=/tmp/ot-socat 103 OT_OUTPUT=/tmp/ot-output 104 socat -d -d pty,raw,echo=0 pty,raw,echo=0 >/dev/null 2>$SOCAT_OUTPUT & 105 timeout_run 10 wait_for_socat 106 echo 'RADIO_PTY' "$RADIO_PTY" 107 echo 'CORE_PTY' "$CORE_PTY" 108 109 RADIO_NCP_PATH="$PWD/build/simulation/examples/apps/ncp/ot-rcp" 110 111 # shellcheck disable=SC2094 112 $RADIO_NCP_PATH 1 >"$RADIO_PTY" <"$RADIO_PTY" & 113 114 # Cover setting a valid network interface name. 115 readonly VALID_NETIF_NAME="wan$(date +%H%M%S)" 116 117 RADIO_URL="spinel+hdlc+uart://${CORE_PTY}?region=US&max-power-table=11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26" 118 119 if [[ ${OT_DAEMON} == 'on' ]]; then 120 sudo -E "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" 2>&1 | tee "${OT_OUTPUT}" & 121 sleep 3 122 # macOS cannot explicitly set network interface name 123 NETIF_NAME=$(grep -o 'Thread interface: .\+' "${OT_OUTPUT}" | cut -d: -f2 | tr -d ' \r\n') 124 OT_CTL_PATH="$PWD/build/posix/src/posix/ot-ctl" 125 if [[ ${OT_DAEMON_ALLOW_ALL} == 1 ]]; then 126 OT_CTL=("${OT_CTL_PATH}") 127 else 128 OT_CTL=(sudo "${OT_CTL_PATH}") 129 fi 130 "${OT_CTL[@]}" -I "${NETIF_NAME}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl' 131 132 # verify supports options in OpenThread commands without separator -- 133 "${OT_CTL[@]}" -I "${NETIF_NAME}" pskc -p 123456 | grep 'Done' || die 'unable to set pskc' 134 135 # verify this reset and factoryreset end immediately 136 "${OT_CTL[@]}" -I "${NETIF_NAME}" reset 137 # sleep a while for daemon ready 138 sleep 2 139 "${OT_CTL[@]}" -I "${NETIF_NAME}" factoryreset 140 # sleep a while for daemon ready 141 sleep 2 142 143 readonly OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH=640 144 local -r kMaxStringLength="$((OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH - 1))" 145 146 # verify success if command length doesn't exceed the limit 147 for len in $(seq 1 ${kMaxStringLength}); do 148 "${OT_CTL[@]}" -I "${NETIF_NAME}" "$(printf '1%.0s' $(seq 1 "${len}"))" 149 done 150 151 # verify failure if command length exceeds the limit 152 len=${OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH} 153 if "${OT_CTL[@]}" -I "${NETIF_NAME}" "$(printf '1%.0s' $(seq 1 "${len}"))"; then 154 die 155 fi 156 OT_CLI_CMD="${OT_CTL[*]} -I ${NETIF_NAME}" 157 else 158 OT_CLI="$PWD/build/posix/src/posix/ot-cli" 159 sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${RADIO_URL}" 160 161 # Cover setting a too long(max is 15 characters) network interface name. 162 # Expect exit code to be 2(OT_EXIT_INVALID_ARGUMENTS). 163 readonly INVALID_NETIF_NAME="wan0123456789123" 164 sudo "${OT_CLI}" -I "${INVALID_NETIF_NAME}" -n "${RADIO_URL}" || test $? = 2 165 166 OT_CLI_CMD="$PWD/build/posix/src/posix/ot-cli ${RADIO_URL}" 167 fi 168 169 sudo expect <<EOF | tee "${OT_OUTPUT}" & 170spawn ${OT_CLI_CMD} 171expect_after { 172 timeout { error } 173} 174send "region\r\n" 175expect "US" 176expect "Done" 177send "panid 0xface\r\n" 178expect "Done" 179send "routerselectionjitter 1\r\n" 180expect "Done" 181send "ifconfig up\r\n" 182expect "Done" 183send "thread start\r\n" 184expect "Done" 185sleep 10 186send "state\r\n" 187expect "leader" 188expect "Done" 189send "extaddr\r\n" 190expect "Done" 191send "dataset active\r\n" 192expect "Done" 193send "ipaddr\r\n" 194expect "Done" 195send "coex\r\n" 196expect "Done" 197send "coap start\r\n" 198expect "Done" 199send "coap resource TestResource\r\n" 200expect "Done" 201send "coap set TestContent\r\n" 202expect "Done" 203set timeout -1 204expect eof 205EOF 206 207 sleep 5 208 209 # wait until the node becomes leader 210 timeout_run 10 wait_for_leader 211 212 # wait coap service start 213 sleep 5 214 215 netstat -an | grep -q 5683 || die 'Application CoAP port is not available!' 216 217 extaddr=$(grep -ao -A +1 'extaddr' $OT_OUTPUT | tail -n1 | tr -d '\r\n\0') 218 echo "Extended address is: ${extaddr}" 219 220 prefix=$(grep -ao 'Mesh Local Prefix: [0-9a-f:]\+' $OT_OUTPUT | cut -d: -f2- | tr -d ' \r\n') 221 LEADER_ALOC="${prefix}ff:fe00:fc00" 222 223 # skip testing CoAP for https://github.com/openthread/openthread/issues/6363 224 [[ $OSTYPE == "linux-gnu"* ]] || return 0 225 226 if [[ ${OT_DAEMON} == 'on' ]]; then 227 sudo killall -9 expect || true 228 sudo killall -9 ot-ctl || true 229 NETIF_INDEX=$(ip link show "${NETIF_NAME}" | cut -f 1 -d ":" | head -n 1) 230 sudo PATH="$(dirname "${OT_CTL_PATH}"):${PATH}" \ 231 python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" "${NETIF_NAME}" \ 232 || die 'multicast group join failed' 233 fi 234 235 # Retrievie test resource through application CoAP 236 coap_response=$(coap-client -B 5 -m GET "coap://[${LEADER_ALOC}]:5683/TestResource") 237 echo "CoAP response is: ${coap_response}" 238 239 # Verify CoAP response contains the test content 240 if [[ ${coap_response} == *TestContent* ]]; then 241 echo 'Success' 242 else 243 die 'Failed to access application CoAP' 244 fi 245 246 # Retrievie extended address through network diagnostic get 247 coap_response=$(echo -n '120100' | xxd -r -p | coap-client -B 5 -m POST "coap://[${LEADER_ALOC}]:61631/d/dg" -f-) 248 249 # Verify Tmf CoAP is blocked 250 if [[ -z ${coap_response} ]]; then 251 die 'Tmf is not blocked' 252 fi 253} 254 255main() 256{ 257 if [[ $# == 0 ]]; then 258 do_build 259 do_check 260 return 0 261 fi 262 263 while [[ $# != 0 ]]; do 264 case $1 in 265 build) 266 do_build 267 ;; 268 check) 269 do_check 270 ;; 271 *) 272 echo "Unknown action: $1" 273 return 1 274 ;; 275 esac 276 shift 277 done 278} 279 280main "$@" 281