| #! /bin/sh |
| |
| # Copyright (c) 2016 Nest Labs, Inc. |
| # All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| |
| |
| display_usage () |
| { |
| echo "Thread Network Retain - Save/Recall thread network info" |
| echo "" |
| echo "Usage: $(basename $0) [primary-net-info-file] [secondary-net-info-file] [wpanctl path] [command]" |
| echo "" |
| echo " Command:" |
| echo " 'S' or 'save' : Save current network info." |
| echo " 'R' or 'recall' : Recall/Restore previously saved network info." |
| echo " 'E' or 'erase' : Erase previously saved network info." |
| echo "" |
| echo " [primary-net-info-file] and [secondary-net-info-file] give full path to files to store network info." |
| echo " [wpanctl path] gives the full path to 'wpanctl'." |
| echo "" |
| } |
| |
| # Check the input args |
| |
| if [ $# -ne 4 ]; then |
| display_usage |
| exit 1 |
| fi |
| |
| primary_file_name="$1" |
| secondary_file_name="$2" |
| wpanctl_command="$3" |
| retain_command=$4 |
| |
| # List of all wpantund properties saved |
| WPANTUND_PROP_NAME="Network:Name" |
| WPANTUND_PROP_KEY="Network:Key" |
| WPANTUND_PROP_PANID="Network:PANID" |
| WPANTUND_PROP_XPANID="Network:XPANID" |
| WPANTUND_PROP_CHANNEL="NCP:Channel" |
| WPANTUND_PROP_MACADDR="NCP:MACAddress" |
| WPANTUND_PROP_NODE_TYPE="Network:NodeType" |
| WPANTUND_PROP_KEY_INDEX="Network:KeyIndex" |
| WPANTUND_PROP_ROUTER_ID="Thread:RouterID" |
| WPANTUND_PROP_PREFERRED_ROUTER_ID="Thread:PreferredRouterID" |
| |
| MAX_ROUTER_ID=60 |
| |
| WPANTUND_PROP_IS_COMMISSIONED="Network:IsCommissioned" |
| WPANTUND_PROP_AUTO_RESUME="Daemon:AutoAssociateAfterReset" |
| |
| cur_name= |
| cur_key= |
| cur_panid= |
| cur_xpanid= |
| cur_channel= |
| cur_macaddr= |
| cur_type= |
| cur_keyindex= |
| cur_routerid= |
| |
| new_name= |
| new_key= |
| new_panid= |
| new_xpanid= |
| new_channel= |
| new_macaddr= |
| new_type= |
| new_keyindex= |
| new_routerid= |
| |
| # Populate the new network info variables by reading the values from wpanctl |
| get_new_network_info_from_wpantund () |
| { |
| val=$($wpanctl_command get -v $WPANTUND_PROP_NAME) |
| val=${val#\"} |
| new_name=${val%\"} |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_KEY) |
| val=${val#*\[} |
| new_key=${val%\]*} |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_PANID) |
| new_panid=$(echo "$val" | sed -e 's/.*=[[:space:]]*//') |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_XPANID) |
| new_xpanid=$(echo "$val" | sed -e 's/.*=[[:space:]]*0x//') |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_CHANNEL) |
| new_channel=$(echo "$val" | sed -e 's/.*=[[:space:]]*//') |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_MACADDR) |
| val=${val#*\[} |
| new_macaddr=${val%\]*} |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_NODE_TYPE) |
| new_type=$(echo "$val" | sed -e 's/.*=[[:space:]]*//') |
| |
| val=$($wpanctl_command get $WPANTUND_PROP_KEY_INDEX) |
| new_keyindex=$(echo "$val" | sed -e 's/.*=[[:space:]]*//') |
| |
| val=$($wpanctl_command get -v $WPANTUND_PROP_ROUTER_ID) |
| new_routerid=$(printf "%d" $val) |
| } |
| |
| restore_network_info_on_wpantund () |
| { |
| # Calculate a new router id value by adding one to it |
| # This ensures router id is different upon every reset/restore |
| router_id=$(($cur_routerid+1)) |
| |
| if [ "$router_id" -ge "$MAX_ROUTER_ID" ] |
| then |
| router_id=0 |
| fi |
| $wpanctl_command set $WPANTUND_PROP_PREFERRED_ROUTER_ID $router_id |
| |
| $wpanctl_command set $WPANTUND_PROP_MACADDR $cur_macaddr |
| $wpanctl_command set $WPANTUND_PROP_NAME $cur_name |
| $wpanctl_command set $WPANTUND_PROP_KEY -d $cur_key |
| $wpanctl_command set $WPANTUND_PROP_PANID $cur_panid |
| $wpanctl_command set $WPANTUND_PROP_XPANID -d $cur_xpanid |
| $wpanctl_command set $WPANTUND_PROP_CHANNEL $cur_channel |
| $wpanctl_command set $WPANTUND_PROP_KEY_INDEX $cur_keyindex |
| |
| $wpanctl_command attach |
| } |
| |
| is_ncp_commissioned () |
| { |
| val=$($wpanctl_command get -v $WPANTUND_PROP_IS_COMMISSIONED) |
| |
| if [ "$val" != "true" ]; then |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| is_auto_resume_enabled () |
| { |
| val=$($wpanctl_command get -v $WPANTUND_PROP_AUTO_RESUME) |
| |
| if [ "$val" != "true" ]; then |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| verify_cur_info () |
| { |
| if [ -z "$cur_name" ] || \ |
| [ -z "$cur_key" ] || \ |
| [ -z "$cur_panid" ] || \ |
| [ -z "$cur_xpanid" ] || \ |
| [ -z "$cur_channel" ] || \ |
| [ -z "$cur_macaddr" ] || \ |
| [ -z "$cur_type" ] || \ |
| [ -z "$cur_keyindex" ] || \ |
| [ -z "$cur_routerid" ] |
| then |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| verify_new_info () |
| { |
| |
| if [ -z "$new_name" ] || \ |
| [ -z "$new_key" ] || \ |
| [ -z "$new_panid" ] || \ |
| [ -z "$new_xpanid" ] || \ |
| [ -z "$new_channel" ] || \ |
| [ -z "$new_macaddr" ] || \ |
| [ -z "$new_type" ] || \ |
| [ -z "$new_keyindex" ] || \ |
| [ -z "$new_routerid" ] |
| then |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| is_new_info_same_as_cur_info () |
| { |
| if [ "$cur_name" != "$new_name" ] || \ |
| [ "$cur_key" != "$new_key" ] || \ |
| [ "$cur_panid" != "$new_panid" ] || \ |
| [ "$cur_xpanid" != "$new_xpanid" ] || \ |
| [ "$cur_channel" != "$new_channel" ] || \ |
| [ "$cur_macaddr" != "$new_macaddr" ] || \ |
| [ "$cur_type" != "$new_type" ] || \ |
| [ "$cur_keyindex" != "$new_keyindex" ] || \ |
| [ "$cur_routerid" != "$new_routerid" ] |
| then |
| return 1 |
| fi |
| |
| return 0 |
| } |
| |
| # Reads and parses the network info from a file and populate old network info variables |
| # First arg ($1) is the file name |
| read_cur_network_info_from_file () |
| { |
| if [ -r $1 ]; then |
| |
| while IFS="\= " read -r key value; do |
| |
| case $key in |
| $WPANTUND_PROP_NAME) |
| cur_name=$value |
| ;; |
| $WPANTUND_PROP_KEY) |
| cur_key=$value |
| ;; |
| $WPANTUND_PROP_PANID) |
| cur_panid=$value |
| ;; |
| $WPANTUND_PROP_XPANID) |
| cur_xpanid=$value |
| ;; |
| $WPANTUND_PROP_CHANNEL) |
| cur_channel=$value |
| ;; |
| $WPANTUND_PROP_MACADDR) |
| cur_macaddr=$value |
| ;; |
| $WPANTUND_PROP_NODE_TYPE) |
| cur_type=$value |
| ;; |
| $WPANTUND_PROP_KEY_INDEX) |
| cur_keyindex=$value |
| ;; |
| $WPANTUND_PROP_ROUTER_ID) |
| cur_routerid=$value |
| ;; |
| esac |
| |
| done < $1 |
| fi |
| } |
| |
| # Writes the new info into a given file name (first arg should be filename) |
| write_new_info_to_file () |
| { |
| fname=$1 |
| |
| if [ -e $fname ]; then |
| rm $fname > /dev/null 2>&1 |
| fi |
| |
| mkdir -p $(dirname "$fname") |
| |
| # Write all the contents to the file |
| |
| echo "${WPANTUND_PROP_NAME} = $new_name" >> $fname |
| echo "${WPANTUND_PROP_KEY} = $new_key" >> $fname |
| echo "${WPANTUND_PROP_PANID} = $new_panid" >> $fname |
| echo "${WPANTUND_PROP_XPANID} = $new_xpanid" >> $fname |
| echo "${WPANTUND_PROP_CHANNEL} = $new_channel" >> $fname |
| echo "${WPANTUND_PROP_MACADDR} = $new_macaddr" >> $fname |
| echo "${WPANTUND_PROP_NODE_TYPE} = $new_type" >> $fname |
| echo "${WPANTUND_PROP_KEY_INDEX} = $new_keyindex" >> $fname |
| echo "${WPANTUND_PROP_ROUTER_ID} = $new_routerid" >> $fname |
| |
| # Add a time stamp |
| echo "# Saved on " $(date) >> $fname |
| } |
| |
| # For test and debugging only |
| display_cur_network_info () |
| { |
| echo "cur_name is" $cur_name |
| echo "cur_key is" $cur_key |
| echo "cur_panid is" $cur_panid |
| echo "cur_xpanid is" $cur_xpanid |
| echo "cur_channel is" $cur_channel |
| echo "cur_macaddr is" $cur_macaddr |
| echo "cur_type is" $cur_type |
| echo "cur_keyindex is" $cur_keyindex |
| echo "cur_routerid is" $cur_routerid |
| } |
| |
| # For test and debugging only |
| display_new_network_info () |
| { |
| echo "new_name is" $new_name |
| echo "new_key is" $new_key |
| echo "new_panid is" $new_panid |
| echo "new_xpanid is" $new_xpanid |
| echo "new_channel is" $new_channel |
| echo "new_macaddr is" $new_macaddr |
| echo "new_type is" $new_type |
| echo "new_keyindex is" $new_keyindex |
| echo "new_routerid is" $new_routerid |
| } |
| |
| save_network_info () |
| { |
| get_new_network_info_from_wpantund |
| |
| read_cur_network_info_from_file $primary_file_name |
| |
| if verify_new_info; then |
| |
| if is_new_info_same_as_cur_info; then |
| echo "Saved network info in \"$primary_file_name\" is up-to-date and valid." |
| else |
| |
| write_new_info_to_file $secondary_file_name |
| |
| # verify the file content match what was written |
| |
| read_cur_network_info_from_file $secondary_file_name |
| |
| if is_new_info_same_as_cur_info; then |
| |
| cp $secondary_file_name $primary_file_name |
| |
| echo "Successfully saved network info in \"$primary_file_name\" and \"$secondary_file_name\"" |
| |
| else |
| echo "ERROR: Could not save the network data" |
| fi |
| # need to figure out if it fails what to do... |
| fi |
| |
| else |
| echo "ERROR: Network info from wpantund is not valid" |
| fi |
| } |
| |
| erase_network_info () |
| { |
| if [ -e $primary_file_name ]; then |
| rm $primary_file_name |
| fi |
| |
| if [ -e $secondary_file_name ]; then |
| rm $secondary_file_name |
| fi |
| |
| echo "Successfully erased network data in \"$primary_file_name\" and \"$secondary_file_name\"". |
| } |
| |
| recall_network_info () |
| { |
| if is_ncp_commissioned; then |
| |
| if is_auto_resume_enabled; then |
| echo "NCP is commissioned and AutoResume is enabled. Skipping recall." |
| return |
| else |
| echo "NCP is commissioned but AutoResume is not enabled. Skipping recall. Resuming instead." |
| $wpanctl_command resume |
| return |
| fi |
| fi |
| |
| echo "NCP is NOT commissioned, trying to recall." |
| |
| read_cur_network_info_from_file $primary_file_name |
| |
| # if no valid data from the main file, try to read from the second (backup) file |
| verify_cur_info || read_cur_network_info_from_file $secondary_file_name |
| |
| if verify_cur_info; then |
| |
| restore_network_info_on_wpantund |
| |
| echo "Successfully recalled network info from \"$primary_file_name\"" |
| else |
| echo "No valid saved network info to recall." |
| fi |
| } |
| |
| case $retain_command in |
| |
| R|recall) |
| recall_network_info |
| ;; |
| |
| S|save) |
| save_network_info |
| ;; |
| |
| E|erase) |
| erase_network_info |
| ;; |
| |
| *) |
| echo "Error: Unknown command \"$retain_command\"" |
| echo " " |
| display_usage |
| ;; |
| esac |
| |
| exit 0 |