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 "dataset init new\r\n" 181expect "Done" 182send "dataset commit active\r\n" 183expect "Done" 184send "routerselectionjitter 1\r\n" 185expect "Done" 186send "ifconfig up\r\n" 187expect "Done" 188send "thread start\r\n" 189expect "Done" 190sleep 10 191send "state\r\n" 192expect "leader" 193expect "Done" 194send "extaddr\r\n" 195expect "Done" 196send "dataset active\r\n" 197expect "Done" 198send "ipaddr\r\n" 199expect "Done" 200send "coex\r\n" 201expect "Done" 202send "coap start\r\n" 203expect "Done" 204send "coap resource TestResource\r\n" 205expect "Done" 206send "coap set TestContent\r\n" 207expect "Done" 208set timeout -1 209expect eof 210EOF 211 212 sleep 5 213 214 # wait until the node becomes leader 215 timeout_run 10 wait_for_leader 216 217 # wait coap service start 218 sleep 5 219 220 netstat -an | grep -q 5683 || die 'Application CoAP port is not available!' 221 222 extaddr=$(grep -ao -A +1 'extaddr' $OT_OUTPUT | tail -n1 | tr -d '\r\n\0') 223 echo "Extended address is: ${extaddr}" 224 225 prefix=$(grep -ao 'Mesh Local Prefix: [0-9a-f:]\+' $OT_OUTPUT | cut -d: -f2- | tr -d ' \r\n') 226 LEADER_ALOC="${prefix}ff:fe00:fc00" 227 228 # skip testing CoAP for https://github.com/openthread/openthread/issues/6363 229 [[ $OSTYPE == "linux-gnu"* ]] || return 0 230 231 if [[ ${OT_DAEMON} == 'on' ]]; then 232 sudo killall -9 expect || true 233 sudo killall -9 ot-ctl || true 234 NETIF_INDEX=$(ip link show "${NETIF_NAME}" | cut -f 1 -d ":" | head -n 1) 235 sudo PATH="$(dirname "${OT_CTL_PATH}"):${PATH}" \ 236 python3 "$PWD/tests/scripts/misc/test_multicast_join.py" "${NETIF_INDEX}" "${NETIF_NAME}" \ 237 || die 'multicast group join failed' 238 fi 239 240 # Retrievie test resource through application CoAP 241 coap_response=$(coap-client -B 5 -m GET "coap://[${LEADER_ALOC}]:5683/TestResource") 242 echo "CoAP response is: ${coap_response}" 243 244 # Verify CoAP response contains the test content 245 if [[ ${coap_response} == *TestContent* ]]; then 246 echo 'Success' 247 else 248 die 'Failed to access application CoAP' 249 fi 250 251 # Retrievie extended address through network diagnostic get 252 coap_response=$(echo -n '120100' | xxd -r -p | coap-client -B 5 -m POST "coap://[${LEADER_ALOC}]:61631/d/dg" -f-) 253 254 # Verify Tmf CoAP is blocked 255 if [[ -z ${coap_response} ]]; then 256 die 'Tmf is not blocked' 257 fi 258} 259 260main() 261{ 262 if [[ $# == 0 ]]; then 263 do_build 264 do_check 265 return 0 266 fi 267 268 while [[ $# != 0 ]]; do 269 case $1 in 270 build) 271 do_build 272 ;; 273 check) 274 do_check 275 ;; 276 *) 277 echo "Unknown action: $1" 278 return 1 279 ;; 280 esac 281 shift 282 done 283} 284 285main "$@" 286