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 VALID_NETIF_NAME="wan$(date +%H%M%S)" 116 readonly VALID_NETIF_NAME 117 118 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" 119 120 if [[ ${OT_DAEMON} == 'on' ]]; then 121 sudo -E "$PWD/build/posix/src/posix/ot-daemon" -d7 -v -I "${VALID_NETIF_NAME}" "${RADIO_URL}" 2>&1 | tee "${OT_OUTPUT}" & 122 sleep 3 123 # macOS cannot explicitly set network interface name 124 NETIF_NAME=$(grep -o 'Thread interface: .\+' "${OT_OUTPUT}" | cut -d: -f2 | tr -d ' \r\n') 125 OT_CTL_PATH="$PWD/build/posix/src/posix/ot-ctl" 126 if [[ ${OT_DAEMON_ALLOW_ALL} == 1 ]]; then 127 OT_CTL=("${OT_CTL_PATH}") 128 else 129 OT_CTL=(sudo "${OT_CTL_PATH}") 130 fi 131 "${OT_CTL[@]}" -I "${NETIF_NAME}" panid 0xface | grep 'Done' || die 'failed to set panid with ot-ctl' 132 133 # verify supports options in OpenThread commands without separator -- 134 "${OT_CTL[@]}" -I "${NETIF_NAME}" pskc -p 123456 | grep 'Done' || die 'unable to set pskc' 135 136 # verify this reset and factoryreset end immediately 137 "${OT_CTL[@]}" -I "${NETIF_NAME}" reset 138 # sleep a while for daemon ready 139 sleep 2 140 "${OT_CTL[@]}" -I "${NETIF_NAME}" factoryreset 141 # sleep a while for daemon ready 142 sleep 2 143 144 OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH=640 145 readonly OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH 146 local -r kMaxStringLength="$((OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH - 1))" 147 148 # verify success if command length doesn't exceed the limit 149 for len in $(seq 1 ${kMaxStringLength}); do 150 "${OT_CTL[@]}" -I "${NETIF_NAME}" "$(printf '1%.0s' $(seq 1 "${len}"))" 151 done 152 153 # verify failure if command length exceeds the limit 154 len=${OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH} 155 if "${OT_CTL[@]}" -I "${NETIF_NAME}" "$(printf '1%.0s' $(seq 1 "${len}"))"; then 156 die 157 fi 158 OT_CLI_CMD="${OT_CTL[*]} -I ${NETIF_NAME}" 159 else 160 OT_CLI="$PWD/build/posix/src/posix/ot-cli" 161 sudo "${OT_CLI}" -I "${VALID_NETIF_NAME}" -n "${RADIO_URL}" 162 163 # Cover setting a too long(max is 15 characters) network interface name. 164 # Expect exit code to be 2(OT_EXIT_INVALID_ARGUMENTS). 165 INVALID_NETIF_NAME="wan0123456789123" 166 readonly INVALID_NETIF_NAME 167 sudo "${OT_CLI}" -I "${INVALID_NETIF_NAME}" -n "${RADIO_URL}" || test $? = 2 168 169 OT_CLI_CMD="$PWD/build/posix/src/posix/ot-cli ${RADIO_URL}" 170 fi 171 172 sudo expect <<EOF | tee "${OT_OUTPUT}" & 173spawn ${OT_CLI_CMD} 174expect_after { 175 timeout { error } 176} 177send "region\r\n" 178expect "US" 179expect "Done" 180send "panid 0xface\r\n" 181expect "Done" 182send "routerselectionjitter 1\r\n" 183expect "Done" 184send "ifconfig up\r\n" 185expect "Done" 186send "thread start\r\n" 187expect "Done" 188sleep 10 189send "state\r\n" 190expect "leader" 191expect "Done" 192send "extaddr\r\n" 193expect "Done" 194send "dataset active\r\n" 195expect "Done" 196send "ipaddr\r\n" 197expect "Done" 198send "coex\r\n" 199expect "Done" 200send "coap start\r\n" 201expect "Done" 202send "coap resource TestResource\r\n" 203expect "Done" 204send "coap set TestContent\r\n" 205expect "Done" 206set timeout -1 207expect eof 208EOF 209 210 sleep 5 211 212 # wait until the node becomes leader 213 timeout_run 10 wait_for_leader 214 215 # wait coap service start 216 sleep 5 217 218 netstat -an | grep -q 5683 || die 'Application CoAP port is not available!' 219 220 extaddr=$(grep -ao -A +1 'extaddr' $OT_OUTPUT | tail -n1 | tr -d '\r\n\0') 221 echo "Extended address is: ${extaddr}" 222 223 prefix=$(grep -ao 'Mesh Local Prefix: [0-9a-f:]\+' $OT_OUTPUT | cut -d: -f2- | tr -d ' \r\n') 224 LEADER_ALOC="${prefix}ff:fe00:fc00" 225 226 # skip testing CoAP for https://github.com/openthread/openthread/issues/6363 227 [[ $OSTYPE == "linux-gnu"* ]] || return 0 228 229 if [[ ${OT_DAEMON} == 'on' ]]; then 230 sudo killall -9 expect || true 231 sudo killall -9 ot-ctl || true 232 NETIF_INDEX=$(ip link show "${NETIF_NAME}" | cut -f 1 -d ":" | head -n 1) 233 sudo PATH="$(dirname "${OT_CTL_PATH}"):${PATH}" \ 234 python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" "${NETIF_NAME}" \ 235 || die 'multicast group join failed' 236 fi 237 238 # Retrievie test resource through application CoAP 239 coap_response=$(coap-client -B 5 -m GET "coap://[${LEADER_ALOC}]:5683/TestResource") 240 echo "CoAP response is: ${coap_response}" 241 242 # Verify CoAP response contains the test content 243 if [[ ${coap_response} == *TestContent* ]]; then 244 echo 'Success' 245 else 246 die 'Failed to access application CoAP' 247 fi 248 249 # Retrievie extended address through network diagnostic get 250 coap_response=$(echo -n '120100' | xxd -r -p | coap-client -B 5 -m POST "coap://[${LEADER_ALOC}]:61631/d/dg" -f-) 251 252 # Verify Tmf CoAP is blocked 253 if [[ -z ${coap_response} ]]; then 254 die 'Tmf is not blocked' 255 fi 256} 257 258main() 259{ 260 if [[ $# == 0 ]]; then 261 do_build 262 do_check 263 return 0 264 fi 265 266 while [[ $# != 0 ]]; do 267 case $1 in 268 build) 269 do_build 270 ;; 271 check) 272 do_check 273 ;; 274 *) 275 echo "Unknown action: $1" 276 return 1 277 ;; 278 esac 279 shift 280 done 281} 282 283main "$@" 284