1*cfb92d14SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*cfb92d14SAndroid Build Coastguard Worker# 3*cfb92d14SAndroid Build Coastguard Worker# Copyright (c) 2018, The OpenThread Authors. 4*cfb92d14SAndroid Build Coastguard Worker# All rights reserved. 5*cfb92d14SAndroid Build Coastguard Worker# 6*cfb92d14SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*cfb92d14SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 8*cfb92d14SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright 9*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 10*cfb92d14SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright 11*cfb92d14SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in the 12*cfb92d14SAndroid Build Coastguard Worker# documentation and/or other materials provided with the distribution. 13*cfb92d14SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the 14*cfb92d14SAndroid Build Coastguard Worker# names of its contributors may be used to endorse or promote products 15*cfb92d14SAndroid Build Coastguard Worker# derived from this software without specific prior written permission. 16*cfb92d14SAndroid Build Coastguard Worker# 17*cfb92d14SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*cfb92d14SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*cfb92d14SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*cfb92d14SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*cfb92d14SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*cfb92d14SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*cfb92d14SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*cfb92d14SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*cfb92d14SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*cfb92d14SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*cfb92d14SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*cfb92d14SAndroid Build Coastguard Worker# 29*cfb92d14SAndroid Build Coastguard Worker 30*cfb92d14SAndroid Build Coastguard Workerimport sys 31*cfb92d14SAndroid Build Coastguard Workerimport os 32*cfb92d14SAndroid Build Coastguard Workerimport time 33*cfb92d14SAndroid Build Coastguard Workerimport re 34*cfb92d14SAndroid Build Coastguard Workerimport random 35*cfb92d14SAndroid Build Coastguard Workerimport weakref 36*cfb92d14SAndroid Build Coastguard Workerimport subprocess 37*cfb92d14SAndroid Build Coastguard Workerimport socket 38*cfb92d14SAndroid Build Coastguard Workerimport asyncore 39*cfb92d14SAndroid Build Coastguard Workerimport inspect 40*cfb92d14SAndroid Build Coastguard Worker 41*cfb92d14SAndroid Build Coastguard Worker# ---------------------------------------------------------------------------------------------------------------------- 42*cfb92d14SAndroid Build Coastguard Worker# wpantund properties 43*cfb92d14SAndroid Build Coastguard Worker 44*cfb92d14SAndroid Build Coastguard WorkerWPAN_STATE = 'NCP:State' 45*cfb92d14SAndroid Build Coastguard WorkerWPAN_NAME = 'Network:Name' 46*cfb92d14SAndroid Build Coastguard WorkerWPAN_PANID = 'Network:PANID' 47*cfb92d14SAndroid Build Coastguard WorkerWPAN_XPANID = 'Network:XPANID' 48*cfb92d14SAndroid Build Coastguard WorkerWPAN_KEY = 'Network:Key' 49*cfb92d14SAndroid Build Coastguard WorkerWPAN_KEY_INDEX = 'Network:KeyIndex' 50*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL = 'NCP:Channel' 51*cfb92d14SAndroid Build Coastguard WorkerWPAN_HW_ADDRESS = 'NCP:HardwareAddress' 52*cfb92d14SAndroid Build Coastguard WorkerWPAN_EXT_ADDRESS = 'NCP:ExtendedAddress' 53*cfb92d14SAndroid Build Coastguard WorkerWPAN_POLL_INTERVAL = 'NCP:SleepyPollInterval' 54*cfb92d14SAndroid Build Coastguard WorkerWPAN_NODE_TYPE = 'Network:NodeType' 55*cfb92d14SAndroid Build Coastguard WorkerWPAN_ROLE = 'Network:Role' 56*cfb92d14SAndroid Build Coastguard WorkerWPAN_PARTITION_ID = 'Network:PartitionId' 57*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_VERSION = 'NCP:Version' 58*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_MCU_POWER_STATE = "NCP:MCUPowerState" 59*cfb92d14SAndroid Build Coastguard WorkerWPAN_NETWORK_PASSTHRU_PORT = 'com.nestlabs.internal:Network:PassthruPort' 60*cfb92d14SAndroid Build Coastguard WorkerWPAN_RCP_VERSION = "POSIXApp:RCPVersion" 61*cfb92d14SAndroid Build Coastguard Worker 62*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_LINK_LOCAL_ADDRESS = "IPv6:LinkLocalAddress" 63*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_MESH_LOCAL_ADDRESS = "IPv6:MeshLocalAddress" 64*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_MESH_LOCAL_PREFIX = "IPv6:MeshLocalPrefix" 65*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_ALL_ADDRESSES = "IPv6:AllAddresses" 66*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_MULTICAST_ADDRESSES = "IPv6:MulticastAddresses" 67*cfb92d14SAndroid Build Coastguard WorkerWPAN_IP6_INTERFACE_ROUTES = "IPv6:Routes" 68*cfb92d14SAndroid Build Coastguard Worker 69*cfb92d14SAndroid Build Coastguard WorkerWPAN_DAEMON_OFF_MESH_ROUTE_AUTO_ADD_ON_INTERFACE = "Daemon:OffMeshRoute:AutoAddOnInterface" 70*cfb92d14SAndroid Build Coastguard WorkerWPAN_DAEMON_OFF_MESH_ROUTE_FILTER_SELF_AUTO_ADDED = "Daemon:OffMeshRoute:FilterSelfAutoAdded" 71*cfb92d14SAndroid Build Coastguard WorkerWPAN_DAEMON_ON_MESH_PREFIX_AUTO_ADD_AS_INTERFACE_ROUTE = "Daemon:OnMeshPrefix:AutoAddAsInterfaceRoute" 72*cfb92d14SAndroid Build Coastguard Worker 73*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_RLOC16 = "Thread:RLOC16" 74*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_ID = "Thread:RouterID" 75*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_LEADER_ADDRESS = "Thread:Leader:Address" 76*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_LEADER_ROUTER_ID = "Thread:Leader:RouterID" 77*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_LEADER_WEIGHT = "Thread:Leader:Weight" 78*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_LEADER_LOCAL_WEIGHT = "Thread:Leader:LocalWeight" 79*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_LEADER_NETWORK_DATA = "Thread:Leader:NetworkData" 80*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_STABLE_LEADER_NETWORK_DATA = "Thread:Leader:StableNetworkData" 81*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NETWORK_DATA = "Thread:NetworkData" 82*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_CHILD_TABLE = "Thread:ChildTable" 83*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_CHILD_TABLE_ASVALMAP = "Thread:ChildTable:AsValMap" 84*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_CHILD_TABLE_ADDRESSES = "Thread:ChildTable:Addresses" 85*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NEIGHBOR_TABLE = "Thread:NeighborTable" 86*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NEIGHBOR_TABLE_ASVALMAP = "Thread:NeighborTable:AsValMap" 87*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NEIGHBOR_TABLE_ERR_RATES = "Thread:NeighborTable:ErrorRates" 88*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NEIGHBOR_TABLE_ERR_RATES_AVVALMAP = "Thread:NeighborTable:ErrorRates:AsValMap" 89*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_TABLE = "Thread:RouterTable" 90*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_TABLE_ASVALMAP = "Thread:RouterTable:AsValMap" 91*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_CHILD_TIMEOUT = "Thread:ChildTimeout" 92*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_PARENT = "Thread:Parent" 93*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_PARENT_ASVALMAP = "Thread:Parent:AsValMap" 94*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_NETWORK_DATA_VERSION = "Thread:NetworkDataVersion" 95*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_STABLE_NETWORK_DATA = "Thread:StableNetworkData" 96*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_STABLE_NETWORK_DATA_VERSION = "Thread:StableNetworkDataVersion" 97*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_PREFERRED_ROUTER_ID = "Thread:PreferredRouterID" 98*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_COMMISSIONER_ENABLED = "Thread:Commissioner:Enabled" 99*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_DEVICE_MODE = "Thread:DeviceMode" 100*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_OFF_MESH_ROUTES = "Thread:OffMeshRoutes" 101*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ON_MESH_PREFIXES = "Thread:OnMeshPrefixes" 102*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_ROLE_ENABLED = "Thread:RouterRole:Enabled" 103*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_CONFIG_FILTER_RLOC_ADDRESSES = "Thread:Config:FilterRLOCAddresses" 104*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_UPGRADE_THRESHOLD = "Thread:RouterUpgradeThreshold" 105*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ROUTER_DOWNGRADE_THRESHOLD = "Thread:RouterDowngradeThreshold" 106*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ACTIVE_DATASET = "Thread:ActiveDataset" 107*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ACTIVE_DATASET_ASVALMAP = "Thread:ActiveDataset:AsValMap" 108*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_PENDING_DATASET = "Thread:PendingDataset" 109*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_PENDING_DATASET_ASVALMAP = "Thread:PendingDataset:AsValMap" 110*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ADDRESS_CACHE_TABLE = "Thread:AddressCacheTable" 111*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_ADDRESS_CACHE_TABLE_ASVALMAP = "Thread:AddressCacheTable:AsValMap" 112*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_JOINER_DISCERNER_VALUE = "Joiner:Discerner:Value" 113*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_JOINER_DISCERNER_BIT_LENGTH = "Joiner:Discerner:BitLength" 114*cfb92d14SAndroid Build Coastguard WorkerWPAN_THREAD_COMMISSIONER_JOINERS = "Commissioner:Joiners" 115*cfb92d14SAndroid Build Coastguard Worker 116*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_LOG_LEVEL = "OpenThread:LogLevel" 117*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_SLAAC_ENABLED = "OpenThread:SLAAC:Enabled" 118*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_STEERING_DATA_ADDRESS = "OpenThread:SteeringData:Address" 119*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_STEERING_DATA_SET_WHEN_JOINABLE = "OpenThread:SteeringData:SetWhenJoinable" 120*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_MSG_BUFFER_COUNTERS = "OpenThread:MsgBufferCounters" 121*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_MSG_BUFFER_COUNTERS_AS_STRING = "OpenThread:MsgBufferCounters:AsString" 122*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_DEBUG_TEST_ASSERT = "OpenThread:Debug:TestAssert" 123*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_DEBUG_TEST_WATCHDOG = "OpenThread:Debug:TestWatchdog" 124*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_SUPPORTED_RADIO_LINKS = "OpenThread:SupportedRadioLinks" 125*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_NEIGHBOR_TABLE_MULTI_RADIO_INFO = "OpenThread:NeighborTable::MultiRadioInfo" 126*cfb92d14SAndroid Build Coastguard WorkerWPAN_OT_TREL_TEST_MODE_ENABLE = "OpenThread:Trel:TestMode:Enable" 127*cfb92d14SAndroid Build Coastguard Worker 128*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_ALLOWLIST_ENABLED = "MAC:Allowlist:Enabled" 129*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_ALLOWLIST_ENTRIES = "MAC:Allowlist:Entries" 130*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_ALLOWLIST_ENTRIES_ASVALMAP = "MAC:Allowlist:Entries:AsValMap" 131*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_DENYLIST_ENABLED = "MAC:Denylist:Enabled" 132*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_DENYLIST_ENTRIES = "MAC:Denylist:Entries" 133*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_DENYLIST_ENTRIES_ASVALMAP = "MAC:Denylist:Entries:AsValMap" 134*cfb92d14SAndroid Build Coastguard Worker 135*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_FILTER_FIXED_RSSI = "MAC:Filter:FixedRssi" 136*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_FILTER_ENTRIES = "MAC:Filter:Entries" 137*cfb92d14SAndroid Build Coastguard WorkerWPAN_MAC_FILTER_ENTRIES_ASVALMAP = "MAC:Filter:Entries:AsValMap" 138*cfb92d14SAndroid Build Coastguard Worker 139*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHILD_SUPERVISION_INTERVAL = "ChildSupervision:Interval" 140*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHILD_SUPERVISION_CHECK_TIMEOUT = "ChildSupervision:CheckTimeout" 141*cfb92d14SAndroid Build Coastguard Worker 142*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_STATUS = "JamDetection:Status" 143*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_ENABLE = "JamDetection:Enable" 144*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_RSSI_THRESHOLD = "JamDetection:RssiThreshold" 145*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_WINDOW = "JamDetection:Window" 146*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_BUSY_PERIOD = "JamDetection:BusyPeriod" 147*cfb92d14SAndroid Build Coastguard WorkerWPAN_JAM_DETECTION_DEBUG_HISTORY_BITMAP = "JamDetection:Debug:HistoryBitmap" 148*cfb92d14SAndroid Build Coastguard Worker 149*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_SAMPLE_INTERVAL = "ChannelMonitor:SampleInterval" 150*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_RSSI_THRESHOLD = "ChannelMonitor:RssiThreshold" 151*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_SAMPLE_WINDOW = "ChannelMonitor:SampleWindow" 152*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_SAMPLE_COUNT = "ChannelMonitor:SampleCount" 153*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_CHANNEL_QUALITY = "ChannelMonitor:ChannelQuality" 154*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MONITOR_CHANNEL_QUALITY_ASVALMAP = "ChannelMonitor:ChannelQuality:AsValMap" 155*cfb92d14SAndroid Build Coastguard Worker 156*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_NEW_CHANNEL = "ChannelManager:NewChannel" 157*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_DELAY = "ChannelManager:Delay" 158*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_CHANNEL_SELECT = "ChannelManager:ChannelSelect" 159*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_AUTO_SELECT_ENABLED = "ChannelManager:AutoSelect:Enabled" 160*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_AUTO_SELECT_INTERVAL = "ChannelManager:AutoSelect:Interval" 161*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_SUPPORTED_CHANNEL_MASK = "ChannelManager:SupportedChannelMask" 162*cfb92d14SAndroid Build Coastguard WorkerWPAN_CHANNEL_MANAGER_FAVORED_CHANNEL_MASK = "ChannelManager:FavoredChannelMask" 163*cfb92d14SAndroid Build Coastguard Worker 164*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_ALL_MAC = "NCP:Counter:AllMac" 165*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_ALL_MAC_ASVALMAP = "NCP:Counter:AllMac:AsValMap" 166*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_TOTAL = "NCP:Counter:TX_PKT_TOTAL" 167*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_UNICAST = "NCP:Counter:TX_PKT_UNICAST" 168*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_BROADCAST = "NCP:Counter:TX_PKT_BROADCAST" 169*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_ACK_REQ = "NCP:Counter:TX_PKT_ACK_REQ" 170*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_ACKED = "NCP:Counter:TX_PKT_ACKED" 171*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_NO_ACK_REQ = "NCP:Counter:TX_PKT_NO_ACK_REQ" 172*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_DATA = "NCP:Counter:TX_PKT_DATA" 173*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_DATA_POLL = "NCP:Counter:TX_PKT_DATA_POLL" 174*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_BEACON = "NCP:Counter:TX_PKT_BEACON" 175*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_BEACON_REQ = "NCP:Counter:TX_PKT_BEACON_REQ" 176*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_OTHER = "NCP:Counter:TX_PKT_OTHER" 177*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_PKT_RETRY = "NCP:Counter:TX_PKT_RETRY" 178*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_ERR_CCA = "NCP:Counter:TX_ERR_CCA" 179*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_ERR_ABORT = "NCP:Counter:TX_ERR_ABORT" 180*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_TOTAL = "NCP:Counter:RX_PKT_TOTAL" 181*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_UNICAST = "NCP:Counter:RX_PKT_UNICAST" 182*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_BROADCAST = "NCP:Counter:RX_PKT_BROADCAST" 183*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_DATA = "NCP:Counter:RX_PKT_DATA" 184*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_DATA_POLL = "NCP:Counter:RX_PKT_DATA_POLL" 185*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_BEACON = "NCP:Counter:RX_PKT_BEACON" 186*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_BEACON_REQ = "NCP:Counter:RX_PKT_BEACON_REQ" 187*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_OTHER = "NCP:Counter:RX_PKT_OTHER" 188*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_FILT_WL = "NCP:Counter:RX_PKT_FILT_WL" 189*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_PKT_FILT_DA = "NCP:Counter:RX_PKT_FILT_DA" 190*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_EMPTY = "NCP:Counter:RX_ERR_EMPTY" 191*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_UKWN_NBR = "NCP:Counter:RX_ERR_UKWN_NBR" 192*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_NVLD_SADDR = "NCP:Counter:RX_ERR_NVLD_SADDR" 193*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_SECURITY = "NCP:Counter:RX_ERR_SECURITY" 194*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_BAD_FCS = "NCP:Counter:RX_ERR_BAD_FCS" 195*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_ERR_OTHER = "NCP:Counter:RX_ERR_OTHER" 196*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_IP_SEC_TOTAL = "NCP:Counter:TX_IP_SEC_TOTAL" 197*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_IP_INSEC_TOTAL = "NCP:Counter:TX_IP_INSEC_TOTAL" 198*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_IP_DROPPED = "NCP:Counter:TX_IP_DROPPED" 199*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_IP_SEC_TOTAL = "NCP:Counter:RX_IP_SEC_TOTAL" 200*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_IP_INSEC_TOTAL = "NCP:Counter:RX_IP_INSEC_TOTAL" 201*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_IP_DROPPED = "NCP:Counter:RX_IP_DROPPED" 202*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_TX_SPINEL_TOTAL = "NCP:Counter:TX_SPINEL_TOTAL" 203*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_SPINEL_TOTAL = "NCP:Counter:RX_SPINEL_TOTAL" 204*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_RX_SPINEL_ERR = "NCP:Counter:RX_SPINEL_ERR" 205*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_IP_TX_SUCCESS = "NCP:Counter:IP_TX_SUCCESS" 206*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_IP_RX_SUCCESS = "NCP:Counter:IP_RX_SUCCESS" 207*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_IP_TX_FAILURE = "NCP:Counter:IP_TX_FAILURE" 208*cfb92d14SAndroid Build Coastguard WorkerWPAN_NCP_COUNTER_IP_RX_FAILURE = "NCP:Counter:IP_RX_FAILURE" 209*cfb92d14SAndroid Build Coastguard Worker 210*cfb92d14SAndroid Build Coastguard Worker# ---------------------------------------------------------------------------------------------------------------------- 211*cfb92d14SAndroid Build Coastguard Worker# Valid state values 212*cfb92d14SAndroid Build Coastguard Worker 213*cfb92d14SAndroid Build Coastguard WorkerSTATE_UNINITIALIZED = '"uninitialized"' 214*cfb92d14SAndroid Build Coastguard WorkerSTATE_FAULT = '"uninitialized:fault"' 215*cfb92d14SAndroid Build Coastguard WorkerSTATE_UPGRADING = '"uninitialized:upgrading"' 216*cfb92d14SAndroid Build Coastguard WorkerSTATE_DEEP_SLEEP = '"offline:deep-sleep"' 217*cfb92d14SAndroid Build Coastguard WorkerSTATE_OFFLINE = '"offline"' 218*cfb92d14SAndroid Build Coastguard WorkerSTATE_COMMISSIONED = '"offline:commissioned"' 219*cfb92d14SAndroid Build Coastguard WorkerSTATE_ASSOCIATING = '"associating"' 220*cfb92d14SAndroid Build Coastguard WorkerSTATE_CREDENTIALS_NEEDED = '"associating:credentials-needed"' 221*cfb92d14SAndroid Build Coastguard WorkerSTATE_ASSOCIATED = '"associated"' 222*cfb92d14SAndroid Build Coastguard WorkerSTATE_ISOLATED = '"associated:no-parent"' 223*cfb92d14SAndroid Build Coastguard WorkerSTATE_NETWAKE_ASLEEP = '"associated:netwake-asleep"' 224*cfb92d14SAndroid Build Coastguard WorkerSTATE_NETWAKE_WAKING = '"associated:netwake-waking"' 225*cfb92d14SAndroid Build Coastguard Worker 226*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 227*cfb92d14SAndroid Build Coastguard Worker# MCU Power state from `WPAN_NCP_MCU_POWER_STATE` 228*cfb92d14SAndroid Build Coastguard Worker 229*cfb92d14SAndroid Build Coastguard WorkerMCU_POWER_STATE_ON = '"on"' 230*cfb92d14SAndroid Build Coastguard WorkerMCU_POWER_STATE_LOW_POWER = '"low-power"' 231*cfb92d14SAndroid Build Coastguard WorkerMCU_POWER_STATE_OFF = '"off"' 232*cfb92d14SAndroid Build Coastguard Worker 233*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 234*cfb92d14SAndroid Build Coastguard Worker# Node Radio Link Types (Use as input to `Node()` initializer) 235*cfb92d14SAndroid Build Coastguard Worker 236*cfb92d14SAndroid Build Coastguard WorkerNODE_15_4 = "-15.4" 237*cfb92d14SAndroid Build Coastguard WorkerNODE_TREL = "-trel" 238*cfb92d14SAndroid Build Coastguard WorkerNODE_15_4_TREL = "-15.4-trel" 239*cfb92d14SAndroid Build Coastguard Worker 240*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 241*cfb92d14SAndroid Build Coastguard Worker# Node types (from `WPAN_NODE_TYPE` property) 242*cfb92d14SAndroid Build Coastguard Worker 243*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_UNKNOWN = '"unknown"' 244*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_LEADER = '"leader"' 245*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_ROUTER = '"router"' 246*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_END_DEVICE = '"end-device"' 247*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_SLEEPY_END_DEVICE = '"sleepy-end-device"' 248*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_COMMISSIONER = '"commissioner"' 249*cfb92d14SAndroid Build Coastguard WorkerNODE_TYPE_NEST_LURKER = '"nl-lurker"' 250*cfb92d14SAndroid Build Coastguard Worker 251*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 252*cfb92d14SAndroid Build Coastguard Worker# Node types used by `Node.join()` 253*cfb92d14SAndroid Build Coastguard Worker 254*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_ROUTER = 'r' 255*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_END_DEVICE = 'e' 256*cfb92d14SAndroid Build Coastguard WorkerJOIN_TYPE_SLEEPY_END_DEVICE = 's' 257*cfb92d14SAndroid Build Coastguard Worker 258*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 259*cfb92d14SAndroid Build Coastguard Worker# Address Cache Table Entry States 260*cfb92d14SAndroid Build Coastguard Worker 261*cfb92d14SAndroid Build Coastguard WorkerADDRESS_CACHE_ENTRY_STATE_CACHED = "cached" 262*cfb92d14SAndroid Build Coastguard WorkerADDRESS_CACHE_ENTRY_STATE_SNOOPED = "snooped" 263*cfb92d14SAndroid Build Coastguard WorkerADDRESS_CACHE_ENTRY_STATE_QUERY = "query" 264*cfb92d14SAndroid Build Coastguard WorkerADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY = "retry-query" 265*cfb92d14SAndroid Build Coastguard Worker 266*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 267*cfb92d14SAndroid Build Coastguard Worker# Bit Flags for Thread Device Mode `WPAN_THREAD_DEVICE_MODE` 268*cfb92d14SAndroid Build Coastguard Worker 269*cfb92d14SAndroid Build Coastguard WorkerTHREAD_MODE_FLAG_FULL_NETWORK_DATA = (1 << 0) 270*cfb92d14SAndroid Build Coastguard WorkerTHREAD_MODE_FLAG_FULL_THREAD_DEV = (1 << 1) 271*cfb92d14SAndroid Build Coastguard WorkerTHREAD_MODE_FLAG_RX_ON_WHEN_IDLE = (1 << 3) 272*cfb92d14SAndroid Build Coastguard Worker 273*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 274*cfb92d14SAndroid Build Coastguard Worker# Radio Link type 275*cfb92d14SAndroid Build Coastguard Worker 276*cfb92d14SAndroid Build Coastguard WorkerRADIO_LINK_IEEE_802_15_4 = "IEEE_802_15_4" 277*cfb92d14SAndroid Build Coastguard WorkerRADIO_LINK_TREL_UDP6 = "TREL_UDP6" 278*cfb92d14SAndroid Build Coastguard WorkerRADIO_LINK_TOBLE = "TOBLE" 279*cfb92d14SAndroid Build Coastguard Worker 280*cfb92d14SAndroid Build Coastguard Worker_OT_BUILDDIR = os.getenv('top_builddir', '../../..') 281*cfb92d14SAndroid Build Coastguard Worker_WPANTUND_PREFIX = os.getenv('WPANTUND_PREFIX', '/usr/local') 282*cfb92d14SAndroid Build Coastguard Worker 283*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 284*cfb92d14SAndroid Build Coastguard Worker 285*cfb92d14SAndroid Build Coastguard Worker 286*cfb92d14SAndroid Build Coastguard Workerdef _log(text, new_line=True, flush=True): 287*cfb92d14SAndroid Build Coastguard Worker sys.stdout.write(text) 288*cfb92d14SAndroid Build Coastguard Worker if new_line: 289*cfb92d14SAndroid Build Coastguard Worker sys.stdout.write('\n') 290*cfb92d14SAndroid Build Coastguard Worker if flush: 291*cfb92d14SAndroid Build Coastguard Worker sys.stdout.flush() 292*cfb92d14SAndroid Build Coastguard Worker 293*cfb92d14SAndroid Build Coastguard Worker 294*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 295*cfb92d14SAndroid Build Coastguard Worker# Node class 296*cfb92d14SAndroid Build Coastguard Worker 297*cfb92d14SAndroid Build Coastguard Worker 298*cfb92d14SAndroid Build Coastguard Workerclass Node(object): 299*cfb92d14SAndroid Build Coastguard Worker """ A wpantund OT NCP instance """ 300*cfb92d14SAndroid Build Coastguard Worker # defines the default verbosity setting (can be changed per `Node`) 301*cfb92d14SAndroid Build Coastguard Worker _VERBOSE = os.getenv('TORANJ_VERBOSE', 'no').lower() in ['true', '1', 't', 'y', 'yes', 'on'] 302*cfb92d14SAndroid Build Coastguard Worker _SPEED_UP_FACTOR = 1 # defines the default time speed up factor 303*cfb92d14SAndroid Build Coastguard Worker 304*cfb92d14SAndroid Build Coastguard Worker # path to `wpantund`, `wpanctl` and `ot-ncp-ftd` 305*cfb92d14SAndroid Build Coastguard Worker _WPANTUND = '%s/sbin/wpantund' % _WPANTUND_PREFIX 306*cfb92d14SAndroid Build Coastguard Worker _WPANCTL = '%s/bin/wpanctl' % _WPANTUND_PREFIX 307*cfb92d14SAndroid Build Coastguard Worker 308*cfb92d14SAndroid Build Coastguard Worker _OT_NCP_FTD = '%s/examples/apps/ncp/ot-ncp-ftd' % _OT_BUILDDIR 309*cfb92d14SAndroid Build Coastguard Worker 310*cfb92d14SAndroid Build Coastguard Worker # determines if the wpantund logs are saved in file or sent to stdout 311*cfb92d14SAndroid Build Coastguard Worker _TUND_LOG_TO_FILE = True 312*cfb92d14SAndroid Build Coastguard Worker # name of wpantund log file (if # name of wpantund _TUND_LOG_TO_FILE is 313*cfb92d14SAndroid Build Coastguard Worker # True) 314*cfb92d14SAndroid Build Coastguard Worker _TUND_LOG_FNAME = 'wpantund-logs' 315*cfb92d14SAndroid Build Coastguard Worker 316*cfb92d14SAndroid Build Coastguard Worker # interface name 317*cfb92d14SAndroid Build Coastguard Worker _INTFC_NAME_PREFIX = 'utun' if sys.platform == 'darwin' else 'wpan' 318*cfb92d14SAndroid Build Coastguard Worker _START_INDEX = 4 if sys.platform == 'darwin' else 1 319*cfb92d14SAndroid Build Coastguard Worker 320*cfb92d14SAndroid Build Coastguard Worker _cur_index = _START_INDEX 321*cfb92d14SAndroid Build Coastguard Worker _all_nodes = weakref.WeakSet() 322*cfb92d14SAndroid Build Coastguard Worker 323*cfb92d14SAndroid Build Coastguard Worker def __init__(self, radios=None, verbose=_VERBOSE): 324*cfb92d14SAndroid Build Coastguard Worker """Creates a new `Node` instance""" 325*cfb92d14SAndroid Build Coastguard Worker 326*cfb92d14SAndroid Build Coastguard Worker index = Node._cur_index 327*cfb92d14SAndroid Build Coastguard Worker Node._cur_index += 1 328*cfb92d14SAndroid Build Coastguard Worker 329*cfb92d14SAndroid Build Coastguard Worker self._index = index 330*cfb92d14SAndroid Build Coastguard Worker self._interface_name = self._INTFC_NAME_PREFIX + str(index) 331*cfb92d14SAndroid Build Coastguard Worker self._verbose = verbose 332*cfb92d14SAndroid Build Coastguard Worker 333*cfb92d14SAndroid Build Coastguard Worker ncp_socket_path = 'system:{}{} {} --time-speed={}'.format(self._OT_NCP_FTD, '' if radios is None else radios, 334*cfb92d14SAndroid Build Coastguard Worker index, self._SPEED_UP_FACTOR) 335*cfb92d14SAndroid Build Coastguard Worker 336*cfb92d14SAndroid Build Coastguard Worker cmd = self._WPANTUND + \ 337*cfb92d14SAndroid Build Coastguard Worker ' -o Config:NCP:SocketPath \"{}\"'.format(ncp_socket_path) + \ 338*cfb92d14SAndroid Build Coastguard Worker ' -o Config:TUN:InterfaceName {}'.format(self._interface_name) + \ 339*cfb92d14SAndroid Build Coastguard Worker ' -o Config:NCP:DriverName spinel' + \ 340*cfb92d14SAndroid Build Coastguard Worker ' -o Daemon:SyslogMask \"all -debug\"' 341*cfb92d14SAndroid Build Coastguard Worker 342*cfb92d14SAndroid Build Coastguard Worker if Node._TUND_LOG_TO_FILE: 343*cfb92d14SAndroid Build Coastguard Worker self._tund_log_file = open(self._TUND_LOG_FNAME + str(index) + '.log', 'wb') 344*cfb92d14SAndroid Build Coastguard Worker else: 345*cfb92d14SAndroid Build Coastguard Worker self._tund_log_file = None 346*cfb92d14SAndroid Build Coastguard Worker 347*cfb92d14SAndroid Build Coastguard Worker if self._verbose: 348*cfb92d14SAndroid Build Coastguard Worker _log('$ Node{}.__init__() cmd: {}'.format(index, cmd)) 349*cfb92d14SAndroid Build Coastguard Worker 350*cfb92d14SAndroid Build Coastguard Worker self._wpantund_process = subprocess.Popen(cmd, shell=True, stderr=self._tund_log_file) 351*cfb92d14SAndroid Build Coastguard Worker 352*cfb92d14SAndroid Build Coastguard Worker self._wpanctl_cmd = self._WPANCTL + ' -I ' + self._interface_name + ' ' 353*cfb92d14SAndroid Build Coastguard Worker 354*cfb92d14SAndroid Build Coastguard Worker # map from local_port to `AsyncReceiver` object 355*cfb92d14SAndroid Build Coastguard Worker self._recvers = weakref.WeakValueDictionary() 356*cfb92d14SAndroid Build Coastguard Worker Node._all_nodes.add(self) 357*cfb92d14SAndroid Build Coastguard Worker 358*cfb92d14SAndroid Build Coastguard Worker def __del__(self): 359*cfb92d14SAndroid Build Coastguard Worker self._wpantund_process.poll() 360*cfb92d14SAndroid Build Coastguard Worker if self._wpantund_process.returncode is None: 361*cfb92d14SAndroid Build Coastguard Worker self._wpantund_process.terminate() 362*cfb92d14SAndroid Build Coastguard Worker self._wpantund_process.wait() 363*cfb92d14SAndroid Build Coastguard Worker 364*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 365*cfb92d14SAndroid Build Coastguard Worker return 'Node (index={}, interface_name={})'.format(self._index, self._interface_name) 366*cfb92d14SAndroid Build Coastguard Worker 367*cfb92d14SAndroid Build Coastguard Worker @property 368*cfb92d14SAndroid Build Coastguard Worker def index(self): 369*cfb92d14SAndroid Build Coastguard Worker return self._index 370*cfb92d14SAndroid Build Coastguard Worker 371*cfb92d14SAndroid Build Coastguard Worker @property 372*cfb92d14SAndroid Build Coastguard Worker def interface_name(self): 373*cfb92d14SAndroid Build Coastguard Worker return self._interface_name 374*cfb92d14SAndroid Build Coastguard Worker 375*cfb92d14SAndroid Build Coastguard Worker @property 376*cfb92d14SAndroid Build Coastguard Worker def tund_log_file(self): 377*cfb92d14SAndroid Build Coastguard Worker return self._tund_log_file 378*cfb92d14SAndroid Build Coastguard Worker 379*cfb92d14SAndroid Build Coastguard Worker # ------------------------------------------------------------------------------------------------------------------ 380*cfb92d14SAndroid Build Coastguard Worker # Executing a `wpanctl` command 381*cfb92d14SAndroid Build Coastguard Worker 382*cfb92d14SAndroid Build Coastguard Worker def wpanctl(self, cmd): 383*cfb92d14SAndroid Build Coastguard Worker """ Runs a wpanctl command on the given wpantund/OT-NCP instance and returns the output """ 384*cfb92d14SAndroid Build Coastguard Worker 385*cfb92d14SAndroid Build Coastguard Worker if self._verbose: 386*cfb92d14SAndroid Build Coastguard Worker _log('$ Node{}.wpanctl(\'{}\')'.format(self._index, cmd), new_line=False) 387*cfb92d14SAndroid Build Coastguard Worker 388*cfb92d14SAndroid Build Coastguard Worker result = subprocess.check_output(self._wpanctl_cmd + cmd, shell=True, stderr=subprocess.STDOUT) 389*cfb92d14SAndroid Build Coastguard Worker 390*cfb92d14SAndroid Build Coastguard Worker if len(result) >= 1 and result[-1] == '\n': # remove the last char if it is '\n', 391*cfb92d14SAndroid Build Coastguard Worker result = result[:-1] 392*cfb92d14SAndroid Build Coastguard Worker 393*cfb92d14SAndroid Build Coastguard Worker if self._verbose: 394*cfb92d14SAndroid Build Coastguard Worker if '\n' in result: 395*cfb92d14SAndroid Build Coastguard Worker _log(':') 396*cfb92d14SAndroid Build Coastguard Worker for line in result.splitlines(): 397*cfb92d14SAndroid Build Coastguard Worker _log(' ' + line) 398*cfb92d14SAndroid Build Coastguard Worker else: 399*cfb92d14SAndroid Build Coastguard Worker _log(' -> \'{}\''.format(result)) 400*cfb92d14SAndroid Build Coastguard Worker 401*cfb92d14SAndroid Build Coastguard Worker return result 402*cfb92d14SAndroid Build Coastguard Worker 403*cfb92d14SAndroid Build Coastguard Worker # ------------------------------------------------------------------------------------------------------------------ 404*cfb92d14SAndroid Build Coastguard Worker # APIs matching `wpanctl` commands. 405*cfb92d14SAndroid Build Coastguard Worker 406*cfb92d14SAndroid Build Coastguard Worker def get(self, prop_name, value_only=True): 407*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('get ' + ('-v ' if value_only else '') + prop_name) 408*cfb92d14SAndroid Build Coastguard Worker 409*cfb92d14SAndroid Build Coastguard Worker def set(self, prop_name, value, binary_data=False): 410*cfb92d14SAndroid Build Coastguard Worker return self._update_prop('set', prop_name, value, binary_data) 411*cfb92d14SAndroid Build Coastguard Worker 412*cfb92d14SAndroid Build Coastguard Worker def add(self, prop_name, value, binary_data=False): 413*cfb92d14SAndroid Build Coastguard Worker return self._update_prop('add', prop_name, value, binary_data) 414*cfb92d14SAndroid Build Coastguard Worker 415*cfb92d14SAndroid Build Coastguard Worker def remove(self, prop_name, value, binary_data=False): 416*cfb92d14SAndroid Build Coastguard Worker return self._update_prop('remove', prop_name, value, binary_data) 417*cfb92d14SAndroid Build Coastguard Worker 418*cfb92d14SAndroid Build Coastguard Worker def _update_prop(self, action, prop_name, value, binary_data): 419*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl(action + ' ' + prop_name + ' ' + ('-d ' if binary_data else '') + '-v ' + 420*cfb92d14SAndroid Build Coastguard Worker value) # use -v to handle values starting with `-`. 421*cfb92d14SAndroid Build Coastguard Worker 422*cfb92d14SAndroid Build Coastguard Worker def reset(self): 423*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('reset') 424*cfb92d14SAndroid Build Coastguard Worker 425*cfb92d14SAndroid Build Coastguard Worker def status(self): 426*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('status') 427*cfb92d14SAndroid Build Coastguard Worker 428*cfb92d14SAndroid Build Coastguard Worker def leave(self): 429*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('leave') 430*cfb92d14SAndroid Build Coastguard Worker 431*cfb92d14SAndroid Build Coastguard Worker def form(self, 432*cfb92d14SAndroid Build Coastguard Worker name, 433*cfb92d14SAndroid Build Coastguard Worker channel=None, 434*cfb92d14SAndroid Build Coastguard Worker channel_mask=None, 435*cfb92d14SAndroid Build Coastguard Worker panid=None, 436*cfb92d14SAndroid Build Coastguard Worker xpanid=None, 437*cfb92d14SAndroid Build Coastguard Worker key=None, 438*cfb92d14SAndroid Build Coastguard Worker key_index=None, 439*cfb92d14SAndroid Build Coastguard Worker node_type=None, 440*cfb92d14SAndroid Build Coastguard Worker mesh_local_prefix=None, 441*cfb92d14SAndroid Build Coastguard Worker legacy_prefix=None): 442*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('form \"' + name + '\"' + (' -c {}'.format(channel) if channel is not None else '') + 443*cfb92d14SAndroid Build Coastguard Worker (' -m {}'.format(channel_mask) if channel_mask is not None else '') + 444*cfb92d14SAndroid Build Coastguard Worker (' -p {}'.format(panid) if panid is not None else '') + 445*cfb92d14SAndroid Build Coastguard Worker (' -x {}'.format(xpanid) if xpanid is not None else '') + 446*cfb92d14SAndroid Build Coastguard Worker (' -k {}'.format(key) if key is not None else '') + 447*cfb92d14SAndroid Build Coastguard Worker (' -i {}'.format(key_index) if key_index is not None else '') + 448*cfb92d14SAndroid Build Coastguard Worker (' -T {}'.format(node_type) if node_type is not None else '') + 449*cfb92d14SAndroid Build Coastguard Worker (' -M {}'.format(mesh_local_prefix) if mesh_local_prefix is not None else '') + 450*cfb92d14SAndroid Build Coastguard Worker (' -L {}'.format(legacy_prefix) if legacy_prefix is not None else '')) 451*cfb92d14SAndroid Build Coastguard Worker 452*cfb92d14SAndroid Build Coastguard Worker def join(self, name, channel=None, node_type=None, panid=None, xpanid=None, key=None): 453*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('join \"' + name + '\"' + (' -c {}'.format(channel) if channel is not None else '') + 454*cfb92d14SAndroid Build Coastguard Worker (' -T {}'.format(node_type) if node_type is not None else '') + 455*cfb92d14SAndroid Build Coastguard Worker (' -p {}'.format(panid) if panid is not None else '') + 456*cfb92d14SAndroid Build Coastguard Worker (' -x {}'.format(xpanid) if xpanid is not None else '') + 457*cfb92d14SAndroid Build Coastguard Worker (' -k {}'.format(key) if key is not None else '') + (' -n')) 458*cfb92d14SAndroid Build Coastguard Worker 459*cfb92d14SAndroid Build Coastguard Worker def active_scan(self, channel=None): 460*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('scan' + (' -c {}'.format(channel) if channel is not None else '')) 461*cfb92d14SAndroid Build Coastguard Worker 462*cfb92d14SAndroid Build Coastguard Worker def energy_scan(self, channel=None): 463*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('scan -e' + (' -c {}'.format(channel) if channel is not None else '')) 464*cfb92d14SAndroid Build Coastguard Worker 465*cfb92d14SAndroid Build Coastguard Worker def discover_scan(self, channel=None, joiner_only=False, enable_filtering=False, panid_filter=None): 466*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('scan -d' + (' -c {}'.format(channel) if channel is not None else '') + 467*cfb92d14SAndroid Build Coastguard Worker (' -j' if joiner_only else '') + (' -f' if enable_filtering else '') + 468*cfb92d14SAndroid Build Coastguard Worker (' -p {}'.format(panid_filter) if panid_filter is not None else '')) 469*cfb92d14SAndroid Build Coastguard Worker 470*cfb92d14SAndroid Build Coastguard Worker def permit_join(self, duration_sec=None, port=None, udp=True, tcp=True): 471*cfb92d14SAndroid Build Coastguard Worker if not udp and not tcp: # incorrect use! 472*cfb92d14SAndroid Build Coastguard Worker return '' 473*cfb92d14SAndroid Build Coastguard Worker traffic_type = '' 474*cfb92d14SAndroid Build Coastguard Worker if udp and not tcp: 475*cfb92d14SAndroid Build Coastguard Worker traffic_type = ' --udp' 476*cfb92d14SAndroid Build Coastguard Worker if tcp and not udp: 477*cfb92d14SAndroid Build Coastguard Worker traffic_type = ' --tcp' 478*cfb92d14SAndroid Build Coastguard Worker if port is not None and duration_sec is None: 479*cfb92d14SAndroid Build Coastguard Worker duration_sec = '240' 480*cfb92d14SAndroid Build Coastguard Worker 481*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('permit-join' + (' {}'.format(duration_sec) if duration_sec is not None else '') + 482*cfb92d14SAndroid Build Coastguard Worker (' {}'.format(port) if port is not None else '') + traffic_type) 483*cfb92d14SAndroid Build Coastguard Worker 484*cfb92d14SAndroid Build Coastguard Worker def config_gateway(self, prefix, default_route=False, priority=None): 485*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('config-gateway ' + prefix + (' -d' if default_route else '') + 486*cfb92d14SAndroid Build Coastguard Worker (' -P {}'.format(priority) if priority is not None else '')) 487*cfb92d14SAndroid Build Coastguard Worker 488*cfb92d14SAndroid Build Coastguard Worker def add_prefix(self, 489*cfb92d14SAndroid Build Coastguard Worker prefix, 490*cfb92d14SAndroid Build Coastguard Worker prefix_len=None, 491*cfb92d14SAndroid Build Coastguard Worker priority=None, 492*cfb92d14SAndroid Build Coastguard Worker stable=True, 493*cfb92d14SAndroid Build Coastguard Worker on_mesh=False, 494*cfb92d14SAndroid Build Coastguard Worker slaac=False, 495*cfb92d14SAndroid Build Coastguard Worker dhcp=False, 496*cfb92d14SAndroid Build Coastguard Worker configure=False, 497*cfb92d14SAndroid Build Coastguard Worker default_route=False, 498*cfb92d14SAndroid Build Coastguard Worker preferred=False): 499*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('add-prefix ' + prefix + (' -l {}'.format(prefix_len) if prefix_len is not None else '') + 500*cfb92d14SAndroid Build Coastguard Worker (' -P {}'.format(priority) if priority is not None else '') + (' -s' if stable else '') + 501*cfb92d14SAndroid Build Coastguard Worker (' -f' if preferred else '') + (' -a' if slaac else '') + (' -d' if dhcp else '') + 502*cfb92d14SAndroid Build Coastguard Worker (' -c' if configure else '') + (' -r' if default_route else '') + 503*cfb92d14SAndroid Build Coastguard Worker (' -o' if on_mesh else '')) 504*cfb92d14SAndroid Build Coastguard Worker 505*cfb92d14SAndroid Build Coastguard Worker def remove_prefix(self, prefix, prefix_len=None): 506*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('remove-prefix ' + prefix + 507*cfb92d14SAndroid Build Coastguard Worker (' -l {}'.format(prefix_len) if prefix_len is not None else '')) 508*cfb92d14SAndroid Build Coastguard Worker 509*cfb92d14SAndroid Build Coastguard Worker def add_route(self, route_prefix, prefix_len=None, priority=None, stable=True): 510*cfb92d14SAndroid Build Coastguard Worker """route priority [(>0 for high, 0 for medium, <0 for low)]""" 511*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('add-route ' + route_prefix + 512*cfb92d14SAndroid Build Coastguard Worker (' -l {}'.format(prefix_len) if prefix_len is not None else '') + 513*cfb92d14SAndroid Build Coastguard Worker (' -p {}'.format(priority) if priority is not None else '') + ('' if stable else ' -n')) 514*cfb92d14SAndroid Build Coastguard Worker 515*cfb92d14SAndroid Build Coastguard Worker def remove_route(self, route_prefix, prefix_len=None, priority=None, stable=True): 516*cfb92d14SAndroid Build Coastguard Worker """route priority [(>0 for high, 0 for medium, <0 for low)]""" 517*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('remove-route ' + route_prefix + 518*cfb92d14SAndroid Build Coastguard Worker (' -l {}'.format(prefix_len) if prefix_len is not None else '') + 519*cfb92d14SAndroid Build Coastguard Worker (' -p {}'.format(priority) if priority is not None else '')) 520*cfb92d14SAndroid Build Coastguard Worker 521*cfb92d14SAndroid Build Coastguard Worker def commissioner_start(self): 522*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('commissioner start') 523*cfb92d14SAndroid Build Coastguard Worker 524*cfb92d14SAndroid Build Coastguard Worker def commissioner_add_joiner(self, eui64, pskd, timeout='100'): 525*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('commissioner joiner-add {} {} {}'.format(eui64, timeout, pskd)) 526*cfb92d14SAndroid Build Coastguard Worker 527*cfb92d14SAndroid Build Coastguard Worker def commissioner_add_joiner_with_discerner(self, discerner_value, discerner_bit_len, pskd, timeout='100'): 528*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('commissioner joiner-add-discerner {} {} {} {}'.format(discerner_value, discerner_bit_len, 529*cfb92d14SAndroid Build Coastguard Worker timeout, pskd)) 530*cfb92d14SAndroid Build Coastguard Worker 531*cfb92d14SAndroid Build Coastguard Worker def joiner_join(self, pskd): 532*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('joiner --join {}'.format(pskd)) 533*cfb92d14SAndroid Build Coastguard Worker 534*cfb92d14SAndroid Build Coastguard Worker def joiner_attach(self): 535*cfb92d14SAndroid Build Coastguard Worker return self.wpanctl('joiner --attach') 536*cfb92d14SAndroid Build Coastguard Worker 537*cfb92d14SAndroid Build Coastguard Worker # ------------------------------------------------------------------------------------------------------------------ 538*cfb92d14SAndroid Build Coastguard Worker # Helper methods 539*cfb92d14SAndroid Build Coastguard Worker 540*cfb92d14SAndroid Build Coastguard Worker def is_associated(self): 541*cfb92d14SAndroid Build Coastguard Worker return self.get(WPAN_STATE) == STATE_ASSOCIATED 542*cfb92d14SAndroid Build Coastguard Worker 543*cfb92d14SAndroid Build Coastguard Worker def join_node(self, node, node_type=JOIN_TYPE_ROUTER, should_set_key=True): 544*cfb92d14SAndroid Build Coastguard Worker """Join a network specified by another node, `node` should be a Node""" 545*cfb92d14SAndroid Build Coastguard Worker 546*cfb92d14SAndroid Build Coastguard Worker if not node.is_associated(): 547*cfb92d14SAndroid Build Coastguard Worker return "{} is not associated".format(node) 548*cfb92d14SAndroid Build Coastguard Worker 549*cfb92d14SAndroid Build Coastguard Worker return self.join(node.get(WPAN_NAME)[1:-1], 550*cfb92d14SAndroid Build Coastguard Worker channel=node.get(WPAN_CHANNEL), 551*cfb92d14SAndroid Build Coastguard Worker node_type=node_type, 552*cfb92d14SAndroid Build Coastguard Worker panid=node.get(WPAN_PANID), 553*cfb92d14SAndroid Build Coastguard Worker xpanid=node.get(WPAN_XPANID), 554*cfb92d14SAndroid Build Coastguard Worker key=node.get(WPAN_KEY)[1:-1] if should_set_key else None) 555*cfb92d14SAndroid Build Coastguard Worker 556*cfb92d14SAndroid Build Coastguard Worker def allowlist_node(self, node): 557*cfb92d14SAndroid Build Coastguard Worker """Adds a given node (of type `Node`) to the allowlist of `self` and enables allowlisting on `self`""" 558*cfb92d14SAndroid Build Coastguard Worker 559*cfb92d14SAndroid Build Coastguard Worker self.add(WPAN_MAC_ALLOWLIST_ENTRIES, node.get(WPAN_EXT_ADDRESS)[1:-1]) 560*cfb92d14SAndroid Build Coastguard Worker self.set(WPAN_MAC_ALLOWLIST_ENABLED, '1') 561*cfb92d14SAndroid Build Coastguard Worker 562*cfb92d14SAndroid Build Coastguard Worker def un_allowlist_node(self, node): 563*cfb92d14SAndroid Build Coastguard Worker """Removes a given node (of node `Node) from the allowlist""" 564*cfb92d14SAndroid Build Coastguard Worker self.remove(WPAN_MAC_ALLOWLIST_ENTRIES, node.get(WPAN_EXT_ADDRESS)[1:-1]) 565*cfb92d14SAndroid Build Coastguard Worker 566*cfb92d14SAndroid Build Coastguard Worker def is_in_scan_result(self, scan_result): 567*cfb92d14SAndroid Build Coastguard Worker """Checks if node is in the scan results 568*cfb92d14SAndroid Build Coastguard Worker `scan_result` must be an array of `ScanResult` object (see `parse_scan_result`). 569*cfb92d14SAndroid Build Coastguard Worker """ 570*cfb92d14SAndroid Build Coastguard Worker panid = self.get(WPAN_PANID) 571*cfb92d14SAndroid Build Coastguard Worker xpanid = self.get(WPAN_XPANID)[2:] 572*cfb92d14SAndroid Build Coastguard Worker name = self.get(WPAN_NAME)[1:-1] 573*cfb92d14SAndroid Build Coastguard Worker channel = self.get(WPAN_CHANNEL) 574*cfb92d14SAndroid Build Coastguard Worker ext_address = self.get(WPAN_EXT_ADDRESS)[1:-1] 575*cfb92d14SAndroid Build Coastguard Worker 576*cfb92d14SAndroid Build Coastguard Worker for item in scan_result: 577*cfb92d14SAndroid Build Coastguard Worker if all([item.panid == panid, item.channel == channel, item.ext_address == ext_address]): 578*cfb92d14SAndroid Build Coastguard Worker if (item.type == ScanResult.TYPE_DISCOVERY_SCAN): 579*cfb92d14SAndroid Build Coastguard Worker if all([item.network_name == name, item.xpanid == xpanid]): 580*cfb92d14SAndroid Build Coastguard Worker return True 581*cfb92d14SAndroid Build Coastguard Worker else: 582*cfb92d14SAndroid Build Coastguard Worker continue 583*cfb92d14SAndroid Build Coastguard Worker return True 584*cfb92d14SAndroid Build Coastguard Worker 585*cfb92d14SAndroid Build Coastguard Worker return False 586*cfb92d14SAndroid Build Coastguard Worker 587*cfb92d14SAndroid Build Coastguard Worker def find_ip6_address_with_prefix(self, prefix): 588*cfb92d14SAndroid Build Coastguard Worker """Find an IPv6 address on node matching a given prefix. 589*cfb92d14SAndroid Build Coastguard Worker `prefix` should be an string containing the prefix. 590*cfb92d14SAndroid Build Coastguard Worker Returns a string containing the IPv6 address matching the prefix or empty string if no address found. 591*cfb92d14SAndroid Build Coastguard Worker """ 592*cfb92d14SAndroid Build Coastguard Worker if len(prefix) > 2 and prefix[-1] == ':' and prefix[-2] == ':': 593*cfb92d14SAndroid Build Coastguard Worker prefix = prefix[:-1] 594*cfb92d14SAndroid Build Coastguard Worker all_addrs = parse_list(self.get(WPAN_IP6_ALL_ADDRESSES)) 595*cfb92d14SAndroid Build Coastguard Worker matched_addr = [addr for addr in all_addrs if addr.startswith(prefix)] 596*cfb92d14SAndroid Build Coastguard Worker return matched_addr[0] if len(matched_addr) >= 1 else '' 597*cfb92d14SAndroid Build Coastguard Worker 598*cfb92d14SAndroid Build Coastguard Worker def add_ip6_address_on_interface(self, address, prefix_len=64): 599*cfb92d14SAndroid Build Coastguard Worker """Adds an IPv6 interface on the network interface. 600*cfb92d14SAndroid Build Coastguard Worker `address` should be string containing the IPv6 address. 601*cfb92d14SAndroid Build Coastguard Worker `prefix_len` is an `int` specifying the prefix length. 602*cfb92d14SAndroid Build Coastguard Worker NOTE: this method uses linux `ip` command. 603*cfb92d14SAndroid Build Coastguard Worker """ 604*cfb92d14SAndroid Build Coastguard Worker cmd = 'ip -6 addr add ' + address + \ 605*cfb92d14SAndroid Build Coastguard Worker '/{} dev '.format(prefix_len) + self.interface_name 606*cfb92d14SAndroid Build Coastguard Worker if self._verbose: 607*cfb92d14SAndroid Build Coastguard Worker _log('$ Node{} \'{}\')'.format(self._index, cmd)) 608*cfb92d14SAndroid Build Coastguard Worker 609*cfb92d14SAndroid Build Coastguard Worker result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) 610*cfb92d14SAndroid Build Coastguard Worker return result 611*cfb92d14SAndroid Build Coastguard Worker 612*cfb92d14SAndroid Build Coastguard Worker def remove_ip6_address_on_interface(self, address, prefix_len=64): 613*cfb92d14SAndroid Build Coastguard Worker """Removes an IPv6 interface on the network interface. 614*cfb92d14SAndroid Build Coastguard Worker `address` should be string containing the IPv6 address. 615*cfb92d14SAndroid Build Coastguard Worker `prefix_len` is an `int` specifying the prefix length. 616*cfb92d14SAndroid Build Coastguard Worker NOTE: this method uses linux `ip` command. 617*cfb92d14SAndroid Build Coastguard Worker """ 618*cfb92d14SAndroid Build Coastguard Worker cmd = 'ip -6 addr del ' + address + \ 619*cfb92d14SAndroid Build Coastguard Worker '/{} dev '.format(prefix_len) + self.interface_name 620*cfb92d14SAndroid Build Coastguard Worker if self._verbose: 621*cfb92d14SAndroid Build Coastguard Worker _log('$ Node{} \'{}\')'.format(self._index, cmd)) 622*cfb92d14SAndroid Build Coastguard Worker 623*cfb92d14SAndroid Build Coastguard Worker result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) 624*cfb92d14SAndroid Build Coastguard Worker return result 625*cfb92d14SAndroid Build Coastguard Worker 626*cfb92d14SAndroid Build Coastguard Worker # ------------------------------------------------------------------------------------------------------------------ 627*cfb92d14SAndroid Build Coastguard Worker # class methods 628*cfb92d14SAndroid Build Coastguard Worker 629*cfb92d14SAndroid Build Coastguard Worker @classmethod 630*cfb92d14SAndroid Build Coastguard Worker def init_all_nodes(cls, disable_logs=not _VERBOSE, wait_time=15): 631*cfb92d14SAndroid Build Coastguard Worker """Issues a `wpanctl.leave` on all `Node` objects and waits for them to be ready""" 632*cfb92d14SAndroid Build Coastguard Worker random.seed(123456) 633*cfb92d14SAndroid Build Coastguard Worker time.sleep(0.5) 634*cfb92d14SAndroid Build Coastguard Worker for node in Node._all_nodes: 635*cfb92d14SAndroid Build Coastguard Worker start_time = time.time() 636*cfb92d14SAndroid Build Coastguard Worker while True: 637*cfb92d14SAndroid Build Coastguard Worker try: 638*cfb92d14SAndroid Build Coastguard Worker node._wpantund_process.poll() 639*cfb92d14SAndroid Build Coastguard Worker if node._wpantund_process.returncode is not None: 640*cfb92d14SAndroid Build Coastguard Worker print('Node {} wpantund instance has terminated unexpectedly'.format(node)) 641*cfb92d14SAndroid Build Coastguard Worker if disable_logs: 642*cfb92d14SAndroid Build Coastguard Worker node.set(WPAN_OT_LOG_LEVEL, '0') 643*cfb92d14SAndroid Build Coastguard Worker node.leave() 644*cfb92d14SAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 645*cfb92d14SAndroid Build Coastguard Worker if (node._verbose): 646*cfb92d14SAndroid Build Coastguard Worker _log(' -> \'{}\' exit code: {}'.format(e.output, e.returncode)) 647*cfb92d14SAndroid Build Coastguard Worker interval = time.time() - start_time 648*cfb92d14SAndroid Build Coastguard Worker if interval > wait_time: 649*cfb92d14SAndroid Build Coastguard Worker print('Took too long to init node {} ({}>{} sec)'.format(node, interval, wait_time)) 650*cfb92d14SAndroid Build Coastguard Worker raise 651*cfb92d14SAndroid Build Coastguard Worker except BaseException: 652*cfb92d14SAndroid Build Coastguard Worker raise 653*cfb92d14SAndroid Build Coastguard Worker else: 654*cfb92d14SAndroid Build Coastguard Worker break 655*cfb92d14SAndroid Build Coastguard Worker time.sleep(0.4) 656*cfb92d14SAndroid Build Coastguard Worker 657*cfb92d14SAndroid Build Coastguard Worker @classmethod 658*cfb92d14SAndroid Build Coastguard Worker def finalize_all_nodes(cls): 659*cfb92d14SAndroid Build Coastguard Worker """Finalizes all previously created `Node` instances (stops the wpantund process)""" 660*cfb92d14SAndroid Build Coastguard Worker for node in Node._all_nodes: 661*cfb92d14SAndroid Build Coastguard Worker node._wpantund_process.terminate() 662*cfb92d14SAndroid Build Coastguard Worker node._wpantund_process.wait() 663*cfb92d14SAndroid Build Coastguard Worker 664*cfb92d14SAndroid Build Coastguard Worker @classmethod 665*cfb92d14SAndroid Build Coastguard Worker def set_time_speedup_factor(cls, factor): 666*cfb92d14SAndroid Build Coastguard Worker """Sets up the time speed up factor - should be set before creating any `Node` objects""" 667*cfb92d14SAndroid Build Coastguard Worker if len(Node._all_nodes) != 0: 668*cfb92d14SAndroid Build Coastguard Worker raise Node._NodeError('set_time_speedup_factor() cannot be called after creating a `Node`') 669*cfb92d14SAndroid Build Coastguard Worker Node._SPEED_UP_FACTOR = factor 670*cfb92d14SAndroid Build Coastguard Worker 671*cfb92d14SAndroid Build Coastguard Worker # ------------------------------------------------------------------------------------------------------------------ 672*cfb92d14SAndroid Build Coastguard Worker # IPv6 message Sender and Receiver class 673*cfb92d14SAndroid Build Coastguard Worker 674*cfb92d14SAndroid Build Coastguard Worker class _NodeError(Exception): 675*cfb92d14SAndroid Build Coastguard Worker pass 676*cfb92d14SAndroid Build Coastguard Worker 677*cfb92d14SAndroid Build Coastguard Worker def prepare_tx(self, src, dst, data=40, count=1, mcast_hops=None): 678*cfb92d14SAndroid Build Coastguard Worker """Prepares an IPv6 msg transmission. 679*cfb92d14SAndroid Build Coastguard Worker 680*cfb92d14SAndroid Build Coastguard Worker - `src` and `dst` can be either a string containing IPv6 address, or a tuple (ipv6 address as string, port), 681*cfb92d14SAndroid Build Coastguard Worker if no port is given, a random port number is used. 682*cfb92d14SAndroid Build Coastguard Worker - `data` can be either a string containing the message to be sent, or an int indicating size of the message (a 683*cfb92d14SAndroid Build Coastguard Worker random message with the given length will be used). 684*cfb92d14SAndroid Build Coastguard Worker - `count` gives number of times the message will be sent (default is 1). 685*cfb92d14SAndroid Build Coastguard Worker - `mcast_hops` specifies multicast hop limit (only applicable for multicast tx). 686*cfb92d14SAndroid Build Coastguard Worker 687*cfb92d14SAndroid Build Coastguard Worker Returns an `AsyncSender` object. 688*cfb92d14SAndroid Build Coastguard Worker 689*cfb92d14SAndroid Build Coastguard Worker """ 690*cfb92d14SAndroid Build Coastguard Worker if isinstance(src, tuple): 691*cfb92d14SAndroid Build Coastguard Worker src_addr = src[0] 692*cfb92d14SAndroid Build Coastguard Worker src_port = src[1] 693*cfb92d14SAndroid Build Coastguard Worker else: 694*cfb92d14SAndroid Build Coastguard Worker src_addr = src 695*cfb92d14SAndroid Build Coastguard Worker src_port = random.randint(49152, 65535) 696*cfb92d14SAndroid Build Coastguard Worker 697*cfb92d14SAndroid Build Coastguard Worker if isinstance(dst, tuple): 698*cfb92d14SAndroid Build Coastguard Worker dst_addr = dst[0] 699*cfb92d14SAndroid Build Coastguard Worker dst_port = dst[1] 700*cfb92d14SAndroid Build Coastguard Worker else: 701*cfb92d14SAndroid Build Coastguard Worker dst_addr = dst 702*cfb92d14SAndroid Build Coastguard Worker dst_port = random.randint(49152, 65535) 703*cfb92d14SAndroid Build Coastguard Worker 704*cfb92d14SAndroid Build Coastguard Worker if isinstance(data, int): 705*cfb92d14SAndroid Build Coastguard Worker # create a random message with the given length. 706*cfb92d14SAndroid Build Coastguard Worker all_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,><?;:[]=-+)(*&^%$#@' 707*cfb92d14SAndroid Build Coastguard Worker msg = ''.join(random.choice(all_chars) for _ in range(data)) 708*cfb92d14SAndroid Build Coastguard Worker else: 709*cfb92d14SAndroid Build Coastguard Worker msg = data 710*cfb92d14SAndroid Build Coastguard Worker 711*cfb92d14SAndroid Build Coastguard Worker return AsyncSender(self, src_addr, src_port, dst_addr, dst_port, msg, count, mcast_hops) 712*cfb92d14SAndroid Build Coastguard Worker 713*cfb92d14SAndroid Build Coastguard Worker def _get_receiver(self, local_port): 714*cfb92d14SAndroid Build Coastguard Worker # Gets or creates a receiver (an `AsyncReceiver`) tied to given port 715*cfb92d14SAndroid Build Coastguard Worker # number 716*cfb92d14SAndroid Build Coastguard Worker if local_port in self._recvers: 717*cfb92d14SAndroid Build Coastguard Worker receiver = self._recvers[local_port] 718*cfb92d14SAndroid Build Coastguard Worker else: 719*cfb92d14SAndroid Build Coastguard Worker receiver = AsyncReceiver(self, local_port) 720*cfb92d14SAndroid Build Coastguard Worker self._recvers[local_port] = receiver 721*cfb92d14SAndroid Build Coastguard Worker return receiver 722*cfb92d14SAndroid Build Coastguard Worker 723*cfb92d14SAndroid Build Coastguard Worker def _remove_recver(self, recvr): 724*cfb92d14SAndroid Build Coastguard Worker # Removes a receiver from weak dictionary - called when the receiver is 725*cfb92d14SAndroid Build Coastguard Worker # done and its socket is closed 726*cfb92d14SAndroid Build Coastguard Worker local_port = recvr.local_port 727*cfb92d14SAndroid Build Coastguard Worker if local_port in self._recvers: 728*cfb92d14SAndroid Build Coastguard Worker del self._recvers[local_port] 729*cfb92d14SAndroid Build Coastguard Worker 730*cfb92d14SAndroid Build Coastguard Worker def prepare_rx(self, sender): 731*cfb92d14SAndroid Build Coastguard Worker """Prepare to receive messages from a sender (an `AsyncSender`)""" 732*cfb92d14SAndroid Build Coastguard Worker receiver = self._get_receiver(sender.dst_port) 733*cfb92d14SAndroid Build Coastguard Worker receiver._add_sender(sender.src_addr, sender.src_port, sender.msg, sender.count) 734*cfb92d14SAndroid Build Coastguard Worker return receiver 735*cfb92d14SAndroid Build Coastguard Worker 736*cfb92d14SAndroid Build Coastguard Worker def prepare_listener(self, local_port, timeout=1): 737*cfb92d14SAndroid Build Coastguard Worker """Prepares a listener (an `AsyncReceiver`) listening on the given `local_port` for given `timeout` (sec)""" 738*cfb92d14SAndroid Build Coastguard Worker receiver = self._get_receiver(local_port) 739*cfb92d14SAndroid Build Coastguard Worker receiver._set_listen_timeout(timeout) 740*cfb92d14SAndroid Build Coastguard Worker return receiver 741*cfb92d14SAndroid Build Coastguard Worker 742*cfb92d14SAndroid Build Coastguard Worker @staticmethod 743*cfb92d14SAndroid Build Coastguard Worker def perform_async_tx_rx(timeout=20): 744*cfb92d14SAndroid Build Coastguard Worker """Called to perform all previously prepared async rx/listen and tx operations""" 745*cfb92d14SAndroid Build Coastguard Worker try: 746*cfb92d14SAndroid Build Coastguard Worker start_time = time.time() 747*cfb92d14SAndroid Build Coastguard Worker while asyncore.socket_map: 748*cfb92d14SAndroid Build Coastguard Worker elapsed_time = time.time() - start_time 749*cfb92d14SAndroid Build Coastguard Worker if elapsed_time > timeout: 750*cfb92d14SAndroid Build Coastguard Worker print('Performing async tx/tx took too long ({}>{} sec)'.format(elapsed_time, timeout)) 751*cfb92d14SAndroid Build Coastguard Worker raise Node._NodeError('perform_tx_rx timed out ({}>{} sec)'.format(elapsed_time, timeout)) 752*cfb92d14SAndroid Build Coastguard Worker # perform a single asyncore loop 753*cfb92d14SAndroid Build Coastguard Worker asyncore.loop(timeout=0.5, count=1) 754*cfb92d14SAndroid Build Coastguard Worker except BaseException: 755*cfb92d14SAndroid Build Coastguard Worker print('Failed to perform async rx/tx') 756*cfb92d14SAndroid Build Coastguard Worker raise 757*cfb92d14SAndroid Build Coastguard Worker 758*cfb92d14SAndroid Build Coastguard Worker 759*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 760*cfb92d14SAndroid Build Coastguard Worker# `AsyncSender` and `AsyncReceiver classes 761*cfb92d14SAndroid Build Coastguard Worker 762*cfb92d14SAndroid Build Coastguard Worker_SO_BINDTODEVICE = 25 763*cfb92d14SAndroid Build Coastguard Worker 764*cfb92d14SAndroid Build Coastguard Worker 765*cfb92d14SAndroid Build Coastguard Workerdef _is_ipv6_addr_link_local(ip_addr): 766*cfb92d14SAndroid Build Coastguard Worker """Indicates if a given IPv6 address is link-local""" 767*cfb92d14SAndroid Build Coastguard Worker return ip_addr.lower().startswith('fe80::') 768*cfb92d14SAndroid Build Coastguard Worker 769*cfb92d14SAndroid Build Coastguard Worker 770*cfb92d14SAndroid Build Coastguard Workerdef _create_socket_address(ip_address, port): 771*cfb92d14SAndroid Build Coastguard Worker """Convert a given IPv6 address (string) and port number into a socket address""" 772*cfb92d14SAndroid Build Coastguard Worker # `socket.getaddrinfo()` returns a list of `(family, socktype, proto, canonname, sockaddr)` where `sockaddr` 773*cfb92d14SAndroid Build Coastguard Worker # (at index 4) can be used as input in socket methods (like `sendto()`, `bind()`, etc.). 774*cfb92d14SAndroid Build Coastguard Worker return socket.getaddrinfo(ip_address, port)[0][4] 775*cfb92d14SAndroid Build Coastguard Worker 776*cfb92d14SAndroid Build Coastguard Worker 777*cfb92d14SAndroid Build Coastguard Workerclass AsyncSender(asyncore.dispatcher): 778*cfb92d14SAndroid Build Coastguard Worker """ An IPv6 async message sender - use `Node.prepare_tx()` to create one""" 779*cfb92d14SAndroid Build Coastguard Worker 780*cfb92d14SAndroid Build Coastguard Worker def __init__(self, node, src_addr, src_port, dst_addr, dst_port, msg, count, mcast_hops=None): 781*cfb92d14SAndroid Build Coastguard Worker self._node = node 782*cfb92d14SAndroid Build Coastguard Worker self._src_addr = src_addr 783*cfb92d14SAndroid Build Coastguard Worker self._src_port = src_port 784*cfb92d14SAndroid Build Coastguard Worker self._dst_addr = dst_addr 785*cfb92d14SAndroid Build Coastguard Worker self._dst_port = dst_port 786*cfb92d14SAndroid Build Coastguard Worker self._msg = msg 787*cfb92d14SAndroid Build Coastguard Worker self._count = count 788*cfb92d14SAndroid Build Coastguard Worker self._dst_sock_addr = _create_socket_address(dst_addr, dst_port) 789*cfb92d14SAndroid Build Coastguard Worker self._tx_buffer = self._msg 790*cfb92d14SAndroid Build Coastguard Worker self._tx_counter = 0 791*cfb92d14SAndroid Build Coastguard Worker 792*cfb92d14SAndroid Build Coastguard Worker # Create a socket, bind it to the node's interface 793*cfb92d14SAndroid Build Coastguard Worker sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 794*cfb92d14SAndroid Build Coastguard Worker sock.setsockopt(socket.SOL_SOCKET, _SO_BINDTODEVICE, node.interface_name + '\0') 795*cfb92d14SAndroid Build Coastguard Worker sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) 796*cfb92d14SAndroid Build Coastguard Worker 797*cfb92d14SAndroid Build Coastguard Worker # Set the IPV6_MULTICAST_HOPS 798*cfb92d14SAndroid Build Coastguard Worker if mcast_hops is not None: 799*cfb92d14SAndroid Build Coastguard Worker sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, mcast_hops) 800*cfb92d14SAndroid Build Coastguard Worker 801*cfb92d14SAndroid Build Coastguard Worker # Bind the socket to the given src address 802*cfb92d14SAndroid Build Coastguard Worker if _is_ipv6_addr_link_local(src_addr): 803*cfb92d14SAndroid Build Coastguard Worker # If src is a link local address it requires the interface name to 804*cfb92d14SAndroid Build Coastguard Worker # be specified. 805*cfb92d14SAndroid Build Coastguard Worker src_sock_addr = _create_socket_address(src_addr + '%' + node.interface_name, src_port) 806*cfb92d14SAndroid Build Coastguard Worker else: 807*cfb92d14SAndroid Build Coastguard Worker src_sock_addr = _create_socket_address(src_addr, src_port) 808*cfb92d14SAndroid Build Coastguard Worker sock.bind(src_sock_addr) 809*cfb92d14SAndroid Build Coastguard Worker 810*cfb92d14SAndroid Build Coastguard Worker asyncore.dispatcher.__init__(self, sock) 811*cfb92d14SAndroid Build Coastguard Worker 812*cfb92d14SAndroid Build Coastguard Worker # Property getters 813*cfb92d14SAndroid Build Coastguard Worker 814*cfb92d14SAndroid Build Coastguard Worker @property 815*cfb92d14SAndroid Build Coastguard Worker def node(self): 816*cfb92d14SAndroid Build Coastguard Worker return self._node 817*cfb92d14SAndroid Build Coastguard Worker 818*cfb92d14SAndroid Build Coastguard Worker @property 819*cfb92d14SAndroid Build Coastguard Worker def src_addr(self): 820*cfb92d14SAndroid Build Coastguard Worker return self._src_addr 821*cfb92d14SAndroid Build Coastguard Worker 822*cfb92d14SAndroid Build Coastguard Worker @property 823*cfb92d14SAndroid Build Coastguard Worker def src_port(self): 824*cfb92d14SAndroid Build Coastguard Worker return self._src_port 825*cfb92d14SAndroid Build Coastguard Worker 826*cfb92d14SAndroid Build Coastguard Worker @property 827*cfb92d14SAndroid Build Coastguard Worker def dst_addr(self): 828*cfb92d14SAndroid Build Coastguard Worker return self._dst_addr 829*cfb92d14SAndroid Build Coastguard Worker 830*cfb92d14SAndroid Build Coastguard Worker @property 831*cfb92d14SAndroid Build Coastguard Worker def dst_port(self): 832*cfb92d14SAndroid Build Coastguard Worker return self._dst_port 833*cfb92d14SAndroid Build Coastguard Worker 834*cfb92d14SAndroid Build Coastguard Worker @property 835*cfb92d14SAndroid Build Coastguard Worker def msg(self): 836*cfb92d14SAndroid Build Coastguard Worker return self._msg 837*cfb92d14SAndroid Build Coastguard Worker 838*cfb92d14SAndroid Build Coastguard Worker @property 839*cfb92d14SAndroid Build Coastguard Worker def count(self): 840*cfb92d14SAndroid Build Coastguard Worker return self._count 841*cfb92d14SAndroid Build Coastguard Worker 842*cfb92d14SAndroid Build Coastguard Worker @property 843*cfb92d14SAndroid Build Coastguard Worker def was_successful(self): 844*cfb92d14SAndroid Build Coastguard Worker """Indicates if the transmission of IPv6 messages finished successfully""" 845*cfb92d14SAndroid Build Coastguard Worker return self._tx_counter == self._count 846*cfb92d14SAndroid Build Coastguard Worker 847*cfb92d14SAndroid Build Coastguard Worker # asyncore.dispatcher callbacks 848*cfb92d14SAndroid Build Coastguard Worker 849*cfb92d14SAndroid Build Coastguard Worker def readable(self): 850*cfb92d14SAndroid Build Coastguard Worker return False 851*cfb92d14SAndroid Build Coastguard Worker 852*cfb92d14SAndroid Build Coastguard Worker def writable(self): 853*cfb92d14SAndroid Build Coastguard Worker return True 854*cfb92d14SAndroid Build Coastguard Worker 855*cfb92d14SAndroid Build Coastguard Worker def handle_write(self): 856*cfb92d14SAndroid Build Coastguard Worker sent_len = self.sendto(self._tx_buffer, self._dst_sock_addr) 857*cfb92d14SAndroid Build Coastguard Worker 858*cfb92d14SAndroid Build Coastguard Worker if self._node._verbose: 859*cfb92d14SAndroid Build Coastguard Worker if sent_len < 30: 860*cfb92d14SAndroid Build Coastguard Worker info_text = '{} bytes ("{}")'.format(sent_len, self._tx_buffer[:sent_len]) 861*cfb92d14SAndroid Build Coastguard Worker else: 862*cfb92d14SAndroid Build Coastguard Worker info_text = '{} bytes'.format(sent_len) 863*cfb92d14SAndroid Build Coastguard Worker _log('- Node{} sent {} to [{}]:{} from [{}]:{}'.format(self._node._index, info_text, self._dst_addr, 864*cfb92d14SAndroid Build Coastguard Worker self._dst_port, self._src_addr, self._src_port)) 865*cfb92d14SAndroid Build Coastguard Worker 866*cfb92d14SAndroid Build Coastguard Worker self._tx_buffer = self._tx_buffer[sent_len:] 867*cfb92d14SAndroid Build Coastguard Worker 868*cfb92d14SAndroid Build Coastguard Worker if len(self._tx_buffer) == 0: 869*cfb92d14SAndroid Build Coastguard Worker self._tx_counter += 1 870*cfb92d14SAndroid Build Coastguard Worker if self._tx_counter < self._count: 871*cfb92d14SAndroid Build Coastguard Worker self._tx_buffer = self._msg 872*cfb92d14SAndroid Build Coastguard Worker else: 873*cfb92d14SAndroid Build Coastguard Worker self.handle_close() 874*cfb92d14SAndroid Build Coastguard Worker 875*cfb92d14SAndroid Build Coastguard Worker def handle_close(self): 876*cfb92d14SAndroid Build Coastguard Worker self.close() 877*cfb92d14SAndroid Build Coastguard Worker 878*cfb92d14SAndroid Build Coastguard Worker 879*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 880*cfb92d14SAndroid Build Coastguard Worker 881*cfb92d14SAndroid Build Coastguard Worker 882*cfb92d14SAndroid Build Coastguard Workerclass AsyncReceiver(asyncore.dispatcher): 883*cfb92d14SAndroid Build Coastguard Worker """ An IPv6 async message receiver - use `prepare_rx()` to create one""" 884*cfb92d14SAndroid Build Coastguard Worker 885*cfb92d14SAndroid Build Coastguard Worker _MAX_RECV_SIZE = 2048 886*cfb92d14SAndroid Build Coastguard Worker 887*cfb92d14SAndroid Build Coastguard Worker class _SenderInfo(object): 888*cfb92d14SAndroid Build Coastguard Worker 889*cfb92d14SAndroid Build Coastguard Worker def __init__(self, sender_addr, sender_port, msg, count): 890*cfb92d14SAndroid Build Coastguard Worker self._sender_addr = sender_addr 891*cfb92d14SAndroid Build Coastguard Worker self._sender_port = sender_port 892*cfb92d14SAndroid Build Coastguard Worker self._msg = msg 893*cfb92d14SAndroid Build Coastguard Worker self._count = count 894*cfb92d14SAndroid Build Coastguard Worker self._rx_counter = 0 895*cfb92d14SAndroid Build Coastguard Worker 896*cfb92d14SAndroid Build Coastguard Worker def _check_received(self, msg, sender_addr, sender_port): 897*cfb92d14SAndroid Build Coastguard Worker if self._msg == msg and self._sender_addr == sender_addr and self._sender_port == sender_port: 898*cfb92d14SAndroid Build Coastguard Worker self._rx_counter += 1 899*cfb92d14SAndroid Build Coastguard Worker return self._did_recv_all() 900*cfb92d14SAndroid Build Coastguard Worker 901*cfb92d14SAndroid Build Coastguard Worker def _did_recv_all(self): 902*cfb92d14SAndroid Build Coastguard Worker return self._rx_counter >= self._count 903*cfb92d14SAndroid Build Coastguard Worker 904*cfb92d14SAndroid Build Coastguard Worker def __init__(self, node, local_port): 905*cfb92d14SAndroid Build Coastguard Worker self._node = node 906*cfb92d14SAndroid Build Coastguard Worker self._local_port = local_port 907*cfb92d14SAndroid Build Coastguard Worker self._senders = [] # list of `_SenderInfo` objects 908*cfb92d14SAndroid Build Coastguard Worker # contains all received messages as a list of (pkt, (src_addr, 909*cfb92d14SAndroid Build Coastguard Worker # src_port)) 910*cfb92d14SAndroid Build Coastguard Worker self._all_rx = [] 911*cfb92d14SAndroid Build Coastguard Worker self._timeout = 0 # listen timeout (zero means forever) 912*cfb92d14SAndroid Build Coastguard Worker self._started = False 913*cfb92d14SAndroid Build Coastguard Worker self._start_time = 0 914*cfb92d14SAndroid Build Coastguard Worker 915*cfb92d14SAndroid Build Coastguard Worker # Create a socket, bind it to the node's interface 916*cfb92d14SAndroid Build Coastguard Worker sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) 917*cfb92d14SAndroid Build Coastguard Worker sock.setsockopt(socket.SOL_SOCKET, _SO_BINDTODEVICE, node.interface_name + '\0') 918*cfb92d14SAndroid Build Coastguard Worker sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) 919*cfb92d14SAndroid Build Coastguard Worker 920*cfb92d14SAndroid Build Coastguard Worker # Bind the socket to any IPv6 address with the given local port 921*cfb92d14SAndroid Build Coastguard Worker local_sock_addr = _create_socket_address('::', local_port) 922*cfb92d14SAndroid Build Coastguard Worker sock.bind(local_sock_addr) 923*cfb92d14SAndroid Build Coastguard Worker 924*cfb92d14SAndroid Build Coastguard Worker asyncore.dispatcher.__init__(self, sock) 925*cfb92d14SAndroid Build Coastguard Worker 926*cfb92d14SAndroid Build Coastguard Worker def _add_sender(self, sender_addr, sender_port, msg, count): 927*cfb92d14SAndroid Build Coastguard Worker self._senders.append(AsyncReceiver._SenderInfo(sender_addr, sender_port, msg, count)) 928*cfb92d14SAndroid Build Coastguard Worker 929*cfb92d14SAndroid Build Coastguard Worker def _set_listen_timeout(self, timeout): 930*cfb92d14SAndroid Build Coastguard Worker self._timeout = timeout 931*cfb92d14SAndroid Build Coastguard Worker 932*cfb92d14SAndroid Build Coastguard Worker # Property getters 933*cfb92d14SAndroid Build Coastguard Worker 934*cfb92d14SAndroid Build Coastguard Worker @property 935*cfb92d14SAndroid Build Coastguard Worker def node(self): 936*cfb92d14SAndroid Build Coastguard Worker return self._node 937*cfb92d14SAndroid Build Coastguard Worker 938*cfb92d14SAndroid Build Coastguard Worker @property 939*cfb92d14SAndroid Build Coastguard Worker def local_port(self): 940*cfb92d14SAndroid Build Coastguard Worker return self._local_port 941*cfb92d14SAndroid Build Coastguard Worker 942*cfb92d14SAndroid Build Coastguard Worker @property 943*cfb92d14SAndroid Build Coastguard Worker def all_rx_msg(self): 944*cfb92d14SAndroid Build Coastguard Worker """returns all received messages as a list of (msg, (src_addr, src_port))""" 945*cfb92d14SAndroid Build Coastguard Worker return self._all_rx 946*cfb92d14SAndroid Build Coastguard Worker 947*cfb92d14SAndroid Build Coastguard Worker @property 948*cfb92d14SAndroid Build Coastguard Worker def was_successful(self): 949*cfb92d14SAndroid Build Coastguard Worker """Indicates if all expected IPv6 messages were received successfully""" 950*cfb92d14SAndroid Build Coastguard Worker return len(self._senders) == 0 or all([sender._did_recv_all() for sender in self._senders]) 951*cfb92d14SAndroid Build Coastguard Worker 952*cfb92d14SAndroid Build Coastguard Worker # asyncore.dispatcher callbacks 953*cfb92d14SAndroid Build Coastguard Worker 954*cfb92d14SAndroid Build Coastguard Worker def readable(self): 955*cfb92d14SAndroid Build Coastguard Worker if not self._started: 956*cfb92d14SAndroid Build Coastguard Worker self._start_time = time.time() 957*cfb92d14SAndroid Build Coastguard Worker self._started = True 958*cfb92d14SAndroid Build Coastguard Worker if self._timeout != 0 and time.time() - self._start_time >= self._timeout: 959*cfb92d14SAndroid Build Coastguard Worker self.handle_close() 960*cfb92d14SAndroid Build Coastguard Worker if self._node._verbose: 961*cfb92d14SAndroid Build Coastguard Worker _log('- Node{} finished listening on port {} for {} sec, received {} msg(s)'.format( 962*cfb92d14SAndroid Build Coastguard Worker self._node._index, self._local_port, self._timeout, len(self._all_rx))) 963*cfb92d14SAndroid Build Coastguard Worker return False 964*cfb92d14SAndroid Build Coastguard Worker return True 965*cfb92d14SAndroid Build Coastguard Worker 966*cfb92d14SAndroid Build Coastguard Worker def writable(self): 967*cfb92d14SAndroid Build Coastguard Worker return False 968*cfb92d14SAndroid Build Coastguard Worker 969*cfb92d14SAndroid Build Coastguard Worker def handle_read(self): 970*cfb92d14SAndroid Build Coastguard Worker (msg, src_sock_addr) = self.recvfrom(AsyncReceiver._MAX_RECV_SIZE) 971*cfb92d14SAndroid Build Coastguard Worker src_addr = src_sock_addr[0] 972*cfb92d14SAndroid Build Coastguard Worker src_port = src_sock_addr[1] 973*cfb92d14SAndroid Build Coastguard Worker 974*cfb92d14SAndroid Build Coastguard Worker if (_is_ipv6_addr_link_local(src_addr)): 975*cfb92d14SAndroid Build Coastguard Worker if '%' in src_addr: 976*cfb92d14SAndroid Build Coastguard Worker # remove the interface name from address 977*cfb92d14SAndroid Build Coastguard Worker src_addr = src_addr.split('%')[0] 978*cfb92d14SAndroid Build Coastguard Worker 979*cfb92d14SAndroid Build Coastguard Worker if self._node._verbose: 980*cfb92d14SAndroid Build Coastguard Worker if len(msg) < 30: 981*cfb92d14SAndroid Build Coastguard Worker info_text = '{} bytes ("{}")'.format(len(msg), msg) 982*cfb92d14SAndroid Build Coastguard Worker else: 983*cfb92d14SAndroid Build Coastguard Worker info_text = '{} bytes'.format(len(msg)) 984*cfb92d14SAndroid Build Coastguard Worker _log('- Node{} received {} on port {} from [{}]:{}'.format(self._node._index, info_text, self._local_port, 985*cfb92d14SAndroid Build Coastguard Worker src_addr, src_port)) 986*cfb92d14SAndroid Build Coastguard Worker 987*cfb92d14SAndroid Build Coastguard Worker self._all_rx.append((msg, (src_addr, src_port))) 988*cfb92d14SAndroid Build Coastguard Worker 989*cfb92d14SAndroid Build Coastguard Worker if all([sender._check_received(msg, src_addr, src_port) for sender in self._senders]): 990*cfb92d14SAndroid Build Coastguard Worker self.handle_close() 991*cfb92d14SAndroid Build Coastguard Worker 992*cfb92d14SAndroid Build Coastguard Worker def handle_close(self): 993*cfb92d14SAndroid Build Coastguard Worker self.close() 994*cfb92d14SAndroid Build Coastguard Worker # remove the receiver from the node once the socket is closed 995*cfb92d14SAndroid Build Coastguard Worker self._node._remove_recver(self) 996*cfb92d14SAndroid Build Coastguard Worker 997*cfb92d14SAndroid Build Coastguard Worker 998*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 999*cfb92d14SAndroid Build Coastguard Worker 1000*cfb92d14SAndroid Build Coastguard Worker 1001*cfb92d14SAndroid Build Coastguard Workerclass VerifyError(Exception): 1002*cfb92d14SAndroid Build Coastguard Worker pass 1003*cfb92d14SAndroid Build Coastguard Worker 1004*cfb92d14SAndroid Build Coastguard Worker 1005*cfb92d14SAndroid Build Coastguard Worker_is_in_verify_within = False 1006*cfb92d14SAndroid Build Coastguard Worker 1007*cfb92d14SAndroid Build Coastguard Worker 1008*cfb92d14SAndroid Build Coastguard Workerdef verify(condition): 1009*cfb92d14SAndroid Build Coastguard Worker """Verifies that a `condition` is true, otherwise raises a VerifyError""" 1010*cfb92d14SAndroid Build Coastguard Worker global _is_in_verify_within 1011*cfb92d14SAndroid Build Coastguard Worker if not condition: 1012*cfb92d14SAndroid Build Coastguard Worker calling_frame = inspect.currentframe().f_back 1013*cfb92d14SAndroid Build Coastguard Worker error_message = 'verify() failed at line {} in "{}"'.format(calling_frame.f_lineno, 1014*cfb92d14SAndroid Build Coastguard Worker calling_frame.f_code.co_filename) 1015*cfb92d14SAndroid Build Coastguard Worker if not _is_in_verify_within: 1016*cfb92d14SAndroid Build Coastguard Worker print(error_message) 1017*cfb92d14SAndroid Build Coastguard Worker raise VerifyError(error_message) 1018*cfb92d14SAndroid Build Coastguard Worker 1019*cfb92d14SAndroid Build Coastguard Worker 1020*cfb92d14SAndroid Build Coastguard Workerdef verify_within(condition_checker_func, wait_time, delay_time=0.1): 1021*cfb92d14SAndroid Build Coastguard Worker """Verifies that a given function `condition_checker_func` passes successfully within a given wait timeout. 1022*cfb92d14SAndroid Build Coastguard Worker `wait_time` is maximum time waiting for condition_checker to pass (in seconds). 1023*cfb92d14SAndroid Build Coastguard Worker `delay_time` specifies a delay interval added between failed attempts (in seconds). 1024*cfb92d14SAndroid Build Coastguard Worker """ 1025*cfb92d14SAndroid Build Coastguard Worker global _is_in_verify_within 1026*cfb92d14SAndroid Build Coastguard Worker start_time = time.time() 1027*cfb92d14SAndroid Build Coastguard Worker old_is_in_verify_within = _is_in_verify_within 1028*cfb92d14SAndroid Build Coastguard Worker _is_in_verify_within = True 1029*cfb92d14SAndroid Build Coastguard Worker while True: 1030*cfb92d14SAndroid Build Coastguard Worker try: 1031*cfb92d14SAndroid Build Coastguard Worker condition_checker_func() 1032*cfb92d14SAndroid Build Coastguard Worker except VerifyError as e: 1033*cfb92d14SAndroid Build Coastguard Worker if time.time() - start_time > wait_time: 1034*cfb92d14SAndroid Build Coastguard Worker print('Took too long to pass the condition ({}>{} sec)'.format(time.time() - start_time, wait_time)) 1035*cfb92d14SAndroid Build Coastguard Worker print(e.message) 1036*cfb92d14SAndroid Build Coastguard Worker raise e 1037*cfb92d14SAndroid Build Coastguard Worker except BaseException: 1038*cfb92d14SAndroid Build Coastguard Worker raise 1039*cfb92d14SAndroid Build Coastguard Worker else: 1040*cfb92d14SAndroid Build Coastguard Worker break 1041*cfb92d14SAndroid Build Coastguard Worker if delay_time != 0: 1042*cfb92d14SAndroid Build Coastguard Worker time.sleep(delay_time) 1043*cfb92d14SAndroid Build Coastguard Worker _is_in_verify_within = old_is_in_verify_within 1044*cfb92d14SAndroid Build Coastguard Worker 1045*cfb92d14SAndroid Build Coastguard Worker 1046*cfb92d14SAndroid Build Coastguard Worker# ----------------------------------------------------------------------------------------------------------------------- 1047*cfb92d14SAndroid Build Coastguard Worker# Parsing `wpanctl` output 1048*cfb92d14SAndroid Build Coastguard Worker 1049*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1050*cfb92d14SAndroid Build Coastguard Worker 1051*cfb92d14SAndroid Build Coastguard Worker 1052*cfb92d14SAndroid Build Coastguard Workerclass ScanResult(object): 1053*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates a scan result (active/discover/energy scan)""" 1054*cfb92d14SAndroid Build Coastguard Worker 1055*cfb92d14SAndroid Build Coastguard Worker TYPE_ACTIVE_SCAN = 'active-scan' 1056*cfb92d14SAndroid Build Coastguard Worker TYPE_DISCOVERY_SCAN = 'discover-scan' 1057*cfb92d14SAndroid Build Coastguard Worker TYPE_ENERGY_SCAN = 'energy-scan' 1058*cfb92d14SAndroid Build Coastguard Worker 1059*cfb92d14SAndroid Build Coastguard Worker def __init__(self, result_text): 1060*cfb92d14SAndroid Build Coastguard Worker 1061*cfb92d14SAndroid Build Coastguard Worker items = [item.strip() for item in result_text.split('|')] 1062*cfb92d14SAndroid Build Coastguard Worker 1063*cfb92d14SAndroid Build Coastguard Worker if len(items) == 2: 1064*cfb92d14SAndroid Build Coastguard Worker self._type = ScanResult.TYPE_ENERGY_SCAN 1065*cfb92d14SAndroid Build Coastguard Worker self._channel = items[0] 1066*cfb92d14SAndroid Build Coastguard Worker self._rssi = items[1] 1067*cfb92d14SAndroid Build Coastguard Worker if len(items) == 7 and '------ NONE ------' in items[1]: 1068*cfb92d14SAndroid Build Coastguard Worker self._type = ScanResult.TYPE_ACTIVE_SCAN 1069*cfb92d14SAndroid Build Coastguard Worker self._index = items[0] 1070*cfb92d14SAndroid Build Coastguard Worker self._panid = items[2] 1071*cfb92d14SAndroid Build Coastguard Worker self._channel = items[3] 1072*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[5] 1073*cfb92d14SAndroid Build Coastguard Worker self._rssi = items[6] 1074*cfb92d14SAndroid Build Coastguard Worker elif len(items) == 7: 1075*cfb92d14SAndroid Build Coastguard Worker self._type = ScanResult.TYPE_DISCOVERY_SCAN 1076*cfb92d14SAndroid Build Coastguard Worker self._index = items[0] 1077*cfb92d14SAndroid Build Coastguard Worker self._network_name = items[1][1:-1] 1078*cfb92d14SAndroid Build Coastguard Worker self._panid = items[2] 1079*cfb92d14SAndroid Build Coastguard Worker self._channel = items[3] 1080*cfb92d14SAndroid Build Coastguard Worker self._xpanid = items[4] 1081*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[5] 1082*cfb92d14SAndroid Build Coastguard Worker self._rssi = items[6] 1083*cfb92d14SAndroid Build Coastguard Worker else: 1084*cfb92d14SAndroid Build Coastguard Worker raise ValueError('"%s" does not seem to be a valid scan result string' % result_text) 1085*cfb92d14SAndroid Build Coastguard Worker 1086*cfb92d14SAndroid Build Coastguard Worker @property 1087*cfb92d14SAndroid Build Coastguard Worker def type(self): 1088*cfb92d14SAndroid Build Coastguard Worker return self._type 1089*cfb92d14SAndroid Build Coastguard Worker 1090*cfb92d14SAndroid Build Coastguard Worker @property 1091*cfb92d14SAndroid Build Coastguard Worker def joinable(self): 1092*cfb92d14SAndroid Build Coastguard Worker return self._joinable 1093*cfb92d14SAndroid Build Coastguard Worker 1094*cfb92d14SAndroid Build Coastguard Worker @property 1095*cfb92d14SAndroid Build Coastguard Worker def network_name(self): 1096*cfb92d14SAndroid Build Coastguard Worker return self._network_name 1097*cfb92d14SAndroid Build Coastguard Worker 1098*cfb92d14SAndroid Build Coastguard Worker @property 1099*cfb92d14SAndroid Build Coastguard Worker def panid(self): 1100*cfb92d14SAndroid Build Coastguard Worker return self._panid 1101*cfb92d14SAndroid Build Coastguard Worker 1102*cfb92d14SAndroid Build Coastguard Worker @property 1103*cfb92d14SAndroid Build Coastguard Worker def channel(self): 1104*cfb92d14SAndroid Build Coastguard Worker return self._channel 1105*cfb92d14SAndroid Build Coastguard Worker 1106*cfb92d14SAndroid Build Coastguard Worker @property 1107*cfb92d14SAndroid Build Coastguard Worker def xpanid(self): 1108*cfb92d14SAndroid Build Coastguard Worker return self._xpanid 1109*cfb92d14SAndroid Build Coastguard Worker 1110*cfb92d14SAndroid Build Coastguard Worker @property 1111*cfb92d14SAndroid Build Coastguard Worker def ext_address(self): 1112*cfb92d14SAndroid Build Coastguard Worker return self._ext_address 1113*cfb92d14SAndroid Build Coastguard Worker 1114*cfb92d14SAndroid Build Coastguard Worker @property 1115*cfb92d14SAndroid Build Coastguard Worker def rssi(self): 1116*cfb92d14SAndroid Build Coastguard Worker return self._rssi 1117*cfb92d14SAndroid Build Coastguard Worker 1118*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1119*cfb92d14SAndroid Build Coastguard Worker return 'ScanResult({})'.format(self.__dict__) 1120*cfb92d14SAndroid Build Coastguard Worker 1121*cfb92d14SAndroid Build Coastguard Worker 1122*cfb92d14SAndroid Build Coastguard Workerdef parse_scan_result(scan_result): 1123*cfb92d14SAndroid Build Coastguard Worker """ Parses scan result string and returns an array of `ScanResult` objects""" 1124*cfb92d14SAndroid Build Coastguard Worker return [ScanResult(item) for item in scan_result.split('\n')[2:]] # skip first two lines which are table headers 1125*cfb92d14SAndroid Build Coastguard Worker 1126*cfb92d14SAndroid Build Coastguard Worker 1127*cfb92d14SAndroid Build Coastguard Workerdef parse_list(list_string): 1128*cfb92d14SAndroid Build Coastguard Worker """ 1129*cfb92d14SAndroid Build Coastguard Worker Parses IPv6/prefix/route list string (output of wpanctl get for properties WPAN_IP6_ALL_ADDRESSES, 1130*cfb92d14SAndroid Build Coastguard Worker IP6_MULTICAST_ADDRESSES, WPAN_THREAD_ON_MESH_PREFIXES, ...) 1131*cfb92d14SAndroid Build Coastguard Worker Returns an array of strings each containing an IPv6/prefix/route entry. 1132*cfb92d14SAndroid Build Coastguard Worker """ 1133*cfb92d14SAndroid Build Coastguard Worker # List string example (get(WPAN_IP6_ALL_ADDRESSES) output): 1134*cfb92d14SAndroid Build Coastguard Worker # 1135*cfb92d14SAndroid Build Coastguard Worker # '[\n 1136*cfb92d14SAndroid Build Coastguard Worker # \t"fdf4:5632:4940:0:8798:8701:85d4:e2be prefix_len:64 origin:ncp valid:forever preferred:forever"\n 1137*cfb92d14SAndroid Build Coastguard Worker # \t"fe80::2092:9358:97ea:71c6 prefix_len:64 origin:ncp valid:forever preferred:forever"\n 1138*cfb92d14SAndroid Build Coastguard Worker # ]' 1139*cfb92d14SAndroid Build Coastguard Worker # 1140*cfb92d14SAndroid Build Coastguard Worker # We split the lines ('\n' as separator) and skip the first and last lines which are '[' and ']'. 1141*cfb92d14SAndroid Build Coastguard Worker # For each line, skip the first two characters (which are '\t"') and last character ('"'), then split the string 1142*cfb92d14SAndroid Build Coastguard Worker # using whitespace as separator. The first entry is the IPv6 address. 1143*cfb92d14SAndroid Build Coastguard Worker # 1144*cfb92d14SAndroid Build Coastguard Worker return [line[2:-1].split()[0] for line in list_string.split('\n')[1:-1]] 1145*cfb92d14SAndroid Build Coastguard Worker 1146*cfb92d14SAndroid Build Coastguard Worker 1147*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1148*cfb92d14SAndroid Build Coastguard Worker 1149*cfb92d14SAndroid Build Coastguard Worker 1150*cfb92d14SAndroid Build Coastguard Workerclass OnMeshPrefix(object): 1151*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates an on-mesh prefix""" 1152*cfb92d14SAndroid Build Coastguard Worker 1153*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1154*cfb92d14SAndroid Build Coastguard Worker 1155*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1156*cfb92d14SAndroid Build Coastguard Worker # 1157*cfb92d14SAndroid Build Coastguard Worker # '\t"fd00:abba:cafe:: prefix_len:64 origin:user stable:yes flags:0x31' 1158*cfb92d14SAndroid Build Coastguard Worker # ' [on-mesh:1 def-route:0 config:0 dhcp:0 slaac:1 pref:1 prio:med] rloc:0x0000"' 1159*cfb92d14SAndroid Build Coastguard Worker 1160*cfb92d14SAndroid Build Coastguard Worker m = re.match( 1161*cfb92d14SAndroid Build Coastguard Worker r'\t"([0-9a-fA-F:]+)\s*prefix_len:(\d+)\s+origin:(\w*)\s+stable:(\w*).* \[' + 1162*cfb92d14SAndroid Build Coastguard Worker r'on-mesh:(\d)\s+def-route:(\d)\s+config:(\d)\s+dhcp:(\d)\s+slaac:(\d)\s+pref:(\d)\s+.*prio:(\w*)\]' + 1163*cfb92d14SAndroid Build Coastguard Worker r'\s+rloc:(0x[0-9a-fA-F]+)', text) 1164*cfb92d14SAndroid Build Coastguard Worker verify(m is not None) 1165*cfb92d14SAndroid Build Coastguard Worker data = m.groups() 1166*cfb92d14SAndroid Build Coastguard Worker 1167*cfb92d14SAndroid Build Coastguard Worker self._prefix = data[0] 1168*cfb92d14SAndroid Build Coastguard Worker self._prefix_len = data[1] 1169*cfb92d14SAndroid Build Coastguard Worker self._origin = data[2] 1170*cfb92d14SAndroid Build Coastguard Worker self._stable = (data[3] == 'yes') 1171*cfb92d14SAndroid Build Coastguard Worker self._on_mesh = (data[4] == '1') 1172*cfb92d14SAndroid Build Coastguard Worker self._def_route = (data[5] == '1') 1173*cfb92d14SAndroid Build Coastguard Worker self._config = (data[6] == '1') 1174*cfb92d14SAndroid Build Coastguard Worker self._dhcp = (data[7] == '1') 1175*cfb92d14SAndroid Build Coastguard Worker self._slaac = (data[8] == '1') 1176*cfb92d14SAndroid Build Coastguard Worker self._preferred = (data[9] == '1') 1177*cfb92d14SAndroid Build Coastguard Worker self._priority = (data[10]) 1178*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = (data[11]) 1179*cfb92d14SAndroid Build Coastguard Worker 1180*cfb92d14SAndroid Build Coastguard Worker @property 1181*cfb92d14SAndroid Build Coastguard Worker def prefix(self): 1182*cfb92d14SAndroid Build Coastguard Worker return self._prefix 1183*cfb92d14SAndroid Build Coastguard Worker 1184*cfb92d14SAndroid Build Coastguard Worker @property 1185*cfb92d14SAndroid Build Coastguard Worker def prefix_len(self): 1186*cfb92d14SAndroid Build Coastguard Worker return self._prefix_len 1187*cfb92d14SAndroid Build Coastguard Worker 1188*cfb92d14SAndroid Build Coastguard Worker @property 1189*cfb92d14SAndroid Build Coastguard Worker def origin(self): 1190*cfb92d14SAndroid Build Coastguard Worker return self._origin 1191*cfb92d14SAndroid Build Coastguard Worker 1192*cfb92d14SAndroid Build Coastguard Worker @property 1193*cfb92d14SAndroid Build Coastguard Worker def priority(self): 1194*cfb92d14SAndroid Build Coastguard Worker return self._priority 1195*cfb92d14SAndroid Build Coastguard Worker 1196*cfb92d14SAndroid Build Coastguard Worker def is_stable(self): 1197*cfb92d14SAndroid Build Coastguard Worker return self._stable 1198*cfb92d14SAndroid Build Coastguard Worker 1199*cfb92d14SAndroid Build Coastguard Worker def is_on_mesh(self): 1200*cfb92d14SAndroid Build Coastguard Worker return self._on_mesh 1201*cfb92d14SAndroid Build Coastguard Worker 1202*cfb92d14SAndroid Build Coastguard Worker def is_def_route(self): 1203*cfb92d14SAndroid Build Coastguard Worker return self._def_route 1204*cfb92d14SAndroid Build Coastguard Worker 1205*cfb92d14SAndroid Build Coastguard Worker def is_config(self): 1206*cfb92d14SAndroid Build Coastguard Worker return self._config 1207*cfb92d14SAndroid Build Coastguard Worker 1208*cfb92d14SAndroid Build Coastguard Worker def is_dhcp(self): 1209*cfb92d14SAndroid Build Coastguard Worker return self._dhcp 1210*cfb92d14SAndroid Build Coastguard Worker 1211*cfb92d14SAndroid Build Coastguard Worker def is_slaac(self): 1212*cfb92d14SAndroid Build Coastguard Worker return self._slaac 1213*cfb92d14SAndroid Build Coastguard Worker 1214*cfb92d14SAndroid Build Coastguard Worker def is_preferred(self): 1215*cfb92d14SAndroid Build Coastguard Worker return self._preferred 1216*cfb92d14SAndroid Build Coastguard Worker 1217*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1218*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1219*cfb92d14SAndroid Build Coastguard Worker 1220*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1221*cfb92d14SAndroid Build Coastguard Worker return 'OnMeshPrefix({})'.format(self.__dict__) 1222*cfb92d14SAndroid Build Coastguard Worker 1223*cfb92d14SAndroid Build Coastguard Worker 1224*cfb92d14SAndroid Build Coastguard Workerdef parse_on_mesh_prefix_result(on_mesh_prefix_list): 1225*cfb92d14SAndroid Build Coastguard Worker """ Parses on-mesh prefix list string and returns an array of `OnMeshPrefix` objects""" 1226*cfb92d14SAndroid Build Coastguard Worker return [OnMeshPrefix(item) for item in on_mesh_prefix_list.split('\n')[1:-1]] 1227*cfb92d14SAndroid Build Coastguard Worker 1228*cfb92d14SAndroid Build Coastguard Worker 1229*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1230*cfb92d14SAndroid Build Coastguard Worker 1231*cfb92d14SAndroid Build Coastguard Worker 1232*cfb92d14SAndroid Build Coastguard Workerclass ChildEntry(object): 1233*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates a child entry""" 1234*cfb92d14SAndroid Build Coastguard Worker 1235*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1236*cfb92d14SAndroid Build Coastguard Worker 1237*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1238*cfb92d14SAndroid Build Coastguard Worker # 1239*cfb92d14SAndroid Build Coastguard Worker # `\t"E24C5F67F4B8CBB9, RLOC16:d402, NetDataVer:175, LQIn:3, AveRssi:-20, LastRssi:-20, Timeout:120, Age:0, ` 1240*cfb92d14SAndroid Build Coastguard Worker # `RxOnIdle:no, FTD:no, SecDataReq:yes, FullNetData:yes"` 1241*cfb92d14SAndroid Build Coastguard Worker # 1242*cfb92d14SAndroid Build Coastguard Worker 1243*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1244*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1245*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1246*cfb92d14SAndroid Build Coastguard Worker 1247*cfb92d14SAndroid Build Coastguard Worker # First item in the extended address 1248*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[0] 1249*cfb92d14SAndroid Build Coastguard Worker 1250*cfb92d14SAndroid Build Coastguard Worker # Convert the rest into a dictionary by splitting using ':' as 1251*cfb92d14SAndroid Build Coastguard Worker # separator 1252*cfb92d14SAndroid Build Coastguard Worker dict = {item.split(':')[0]: item.split(':')[1] for item in items[1:]} 1253*cfb92d14SAndroid Build Coastguard Worker 1254*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = dict['RLOC16'] 1255*cfb92d14SAndroid Build Coastguard Worker self._timeout = dict['Timeout'] 1256*cfb92d14SAndroid Build Coastguard Worker self._rx_on_idle = (dict['RxOnIdle'] == 'yes') 1257*cfb92d14SAndroid Build Coastguard Worker self._ftd = (dict['FTD'] == 'yes') 1258*cfb92d14SAndroid Build Coastguard Worker self._sec_data_req = (dict['SecDataReq'] == 'yes') 1259*cfb92d14SAndroid Build Coastguard Worker self._full_net_data = (dict['FullNetData'] == 'yes') 1260*cfb92d14SAndroid Build Coastguard Worker 1261*cfb92d14SAndroid Build Coastguard Worker @property 1262*cfb92d14SAndroid Build Coastguard Worker def ext_address(self): 1263*cfb92d14SAndroid Build Coastguard Worker return self._ext_address 1264*cfb92d14SAndroid Build Coastguard Worker 1265*cfb92d14SAndroid Build Coastguard Worker @property 1266*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1267*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1268*cfb92d14SAndroid Build Coastguard Worker 1269*cfb92d14SAndroid Build Coastguard Worker @property 1270*cfb92d14SAndroid Build Coastguard Worker def timeout(self): 1271*cfb92d14SAndroid Build Coastguard Worker return self._timeout 1272*cfb92d14SAndroid Build Coastguard Worker 1273*cfb92d14SAndroid Build Coastguard Worker def is_rx_on_when_idle(self): 1274*cfb92d14SAndroid Build Coastguard Worker return self._rx_on_idle 1275*cfb92d14SAndroid Build Coastguard Worker 1276*cfb92d14SAndroid Build Coastguard Worker def is_ftd(self): 1277*cfb92d14SAndroid Build Coastguard Worker return self._ftd 1278*cfb92d14SAndroid Build Coastguard Worker 1279*cfb92d14SAndroid Build Coastguard Worker def is_sec_data_req(self): 1280*cfb92d14SAndroid Build Coastguard Worker return self._sec_data_req 1281*cfb92d14SAndroid Build Coastguard Worker 1282*cfb92d14SAndroid Build Coastguard Worker def is_full_net_data(self): 1283*cfb92d14SAndroid Build Coastguard Worker return self._full_net_data 1284*cfb92d14SAndroid Build Coastguard Worker 1285*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1286*cfb92d14SAndroid Build Coastguard Worker return 'ChildEntry({})'.format(self.__dict__) 1287*cfb92d14SAndroid Build Coastguard Worker 1288*cfb92d14SAndroid Build Coastguard Worker 1289*cfb92d14SAndroid Build Coastguard Workerdef parse_child_table_result(child_table_list): 1290*cfb92d14SAndroid Build Coastguard Worker """ Parses child table list string and returns an array of `ChildEntry` objects""" 1291*cfb92d14SAndroid Build Coastguard Worker return [ChildEntry(item) for item in child_table_list.split('\n')[1:-1]] 1292*cfb92d14SAndroid Build Coastguard Worker 1293*cfb92d14SAndroid Build Coastguard Worker 1294*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1295*cfb92d14SAndroid Build Coastguard Worker 1296*cfb92d14SAndroid Build Coastguard Worker 1297*cfb92d14SAndroid Build Coastguard Workerclass NeighborEntry(object): 1298*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates a neighbor entry""" 1299*cfb92d14SAndroid Build Coastguard Worker 1300*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1301*cfb92d14SAndroid Build Coastguard Worker 1302*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1303*cfb92d14SAndroid Build Coastguard Worker # 1304*cfb92d14SAndroid Build Coastguard Worker # `\t"5AC95ED4646D6565, RLOC16:9403, LQIn:3, AveRssi:-20, LastRssi:-20, Age:0, LinkFC:8, MleFC:0, IsChild:yes,' 1305*cfb92d14SAndroid Build Coastguard Worker # 'RxOnIdle:no, FTD:no, SecDataReq:yes, FullNetData:yes"' 1306*cfb92d14SAndroid Build Coastguard Worker # 1307*cfb92d14SAndroid Build Coastguard Worker 1308*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1309*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1310*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1311*cfb92d14SAndroid Build Coastguard Worker 1312*cfb92d14SAndroid Build Coastguard Worker # First item in the extended address 1313*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[0] 1314*cfb92d14SAndroid Build Coastguard Worker 1315*cfb92d14SAndroid Build Coastguard Worker # Convert the rest into a dictionary by splitting the text using ':' as 1316*cfb92d14SAndroid Build Coastguard Worker # separator 1317*cfb92d14SAndroid Build Coastguard Worker dict = {item.split(':')[0]: item.split(':')[1] for item in items[1:]} 1318*cfb92d14SAndroid Build Coastguard Worker 1319*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = dict['RLOC16'] 1320*cfb92d14SAndroid Build Coastguard Worker self._is_child = (dict['IsChild'] == 'yes') 1321*cfb92d14SAndroid Build Coastguard Worker self._rx_on_idle = (dict['RxOnIdle'] == 'yes') 1322*cfb92d14SAndroid Build Coastguard Worker self._ftd = (dict['FTD'] == 'yes') 1323*cfb92d14SAndroid Build Coastguard Worker 1324*cfb92d14SAndroid Build Coastguard Worker @property 1325*cfb92d14SAndroid Build Coastguard Worker def ext_address(self): 1326*cfb92d14SAndroid Build Coastguard Worker return self._ext_address 1327*cfb92d14SAndroid Build Coastguard Worker 1328*cfb92d14SAndroid Build Coastguard Worker @property 1329*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1330*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1331*cfb92d14SAndroid Build Coastguard Worker 1332*cfb92d14SAndroid Build Coastguard Worker def is_rx_on_when_idle(self): 1333*cfb92d14SAndroid Build Coastguard Worker return self._rx_on_idle 1334*cfb92d14SAndroid Build Coastguard Worker 1335*cfb92d14SAndroid Build Coastguard Worker def is_ftd(self): 1336*cfb92d14SAndroid Build Coastguard Worker return self._ftd 1337*cfb92d14SAndroid Build Coastguard Worker 1338*cfb92d14SAndroid Build Coastguard Worker def is_child(self): 1339*cfb92d14SAndroid Build Coastguard Worker return self._is_child 1340*cfb92d14SAndroid Build Coastguard Worker 1341*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1342*cfb92d14SAndroid Build Coastguard Worker return 'NeighborEntry({})'.format(self.__dict__) 1343*cfb92d14SAndroid Build Coastguard Worker 1344*cfb92d14SAndroid Build Coastguard Worker 1345*cfb92d14SAndroid Build Coastguard Workerdef parse_neighbor_table_result(neighbor_table_list): 1346*cfb92d14SAndroid Build Coastguard Worker """ Parses neighbor table list string and returns an array of `NeighborEntry` objects""" 1347*cfb92d14SAndroid Build Coastguard Worker return [NeighborEntry(item) for item in neighbor_table_list.split('\n')[1:-1]] 1348*cfb92d14SAndroid Build Coastguard Worker 1349*cfb92d14SAndroid Build Coastguard Worker 1350*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1351*cfb92d14SAndroid Build Coastguard Worker 1352*cfb92d14SAndroid Build Coastguard Worker 1353*cfb92d14SAndroid Build Coastguard Workerclass RouterTableEntry(object): 1354*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates a router table entry""" 1355*cfb92d14SAndroid Build Coastguard Worker 1356*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1357*cfb92d14SAndroid Build Coastguard Worker 1358*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1359*cfb92d14SAndroid Build Coastguard Worker # 1360*cfb92d14SAndroid Build Coastguard Worker # `\t"8A970B3251810826, RLOC16:4000, RouterId:16, NextHop:43, PathCost:1, LQIn:3, LQOut:3, Age:3, LinkEst:yes"` 1361*cfb92d14SAndroid Build Coastguard Worker # 1362*cfb92d14SAndroid Build Coastguard Worker 1363*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1364*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1365*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1366*cfb92d14SAndroid Build Coastguard Worker 1367*cfb92d14SAndroid Build Coastguard Worker # First item in the extended address 1368*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[0] 1369*cfb92d14SAndroid Build Coastguard Worker 1370*cfb92d14SAndroid Build Coastguard Worker # Convert the rest into a dictionary by splitting the text using ':' as 1371*cfb92d14SAndroid Build Coastguard Worker # separator 1372*cfb92d14SAndroid Build Coastguard Worker dict = {item.split(':')[0]: item.split(':')[1] for item in items[1:]} 1373*cfb92d14SAndroid Build Coastguard Worker 1374*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = int(dict['RLOC16'], 16) 1375*cfb92d14SAndroid Build Coastguard Worker self._router_id = int(dict['RouterId'], 0) 1376*cfb92d14SAndroid Build Coastguard Worker self._next_hop = int(dict['NextHop'], 0) 1377*cfb92d14SAndroid Build Coastguard Worker self._path_cost = int(dict['PathCost'], 0) 1378*cfb92d14SAndroid Build Coastguard Worker self._age = int(dict['Age'], 0) 1379*cfb92d14SAndroid Build Coastguard Worker self._le = (dict['LinkEst'] == 'yes') 1380*cfb92d14SAndroid Build Coastguard Worker 1381*cfb92d14SAndroid Build Coastguard Worker @property 1382*cfb92d14SAndroid Build Coastguard Worker def ext_address(self): 1383*cfb92d14SAndroid Build Coastguard Worker return self._ext_address 1384*cfb92d14SAndroid Build Coastguard Worker 1385*cfb92d14SAndroid Build Coastguard Worker @property 1386*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1387*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1388*cfb92d14SAndroid Build Coastguard Worker 1389*cfb92d14SAndroid Build Coastguard Worker @property 1390*cfb92d14SAndroid Build Coastguard Worker def router_id(self): 1391*cfb92d14SAndroid Build Coastguard Worker return self._router_id 1392*cfb92d14SAndroid Build Coastguard Worker 1393*cfb92d14SAndroid Build Coastguard Worker @property 1394*cfb92d14SAndroid Build Coastguard Worker def next_hop(self): 1395*cfb92d14SAndroid Build Coastguard Worker return self._next_hop 1396*cfb92d14SAndroid Build Coastguard Worker 1397*cfb92d14SAndroid Build Coastguard Worker @property 1398*cfb92d14SAndroid Build Coastguard Worker def path_cost(self): 1399*cfb92d14SAndroid Build Coastguard Worker return self._path_cost 1400*cfb92d14SAndroid Build Coastguard Worker 1401*cfb92d14SAndroid Build Coastguard Worker def is_link_established(self): 1402*cfb92d14SAndroid Build Coastguard Worker return self._le 1403*cfb92d14SAndroid Build Coastguard Worker 1404*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1405*cfb92d14SAndroid Build Coastguard Worker return 'RouterTableEntry({})'.format(self.__dict__) 1406*cfb92d14SAndroid Build Coastguard Worker 1407*cfb92d14SAndroid Build Coastguard Worker 1408*cfb92d14SAndroid Build Coastguard Workerdef parse_router_table_result(router_table_list): 1409*cfb92d14SAndroid Build Coastguard Worker """ Parses router table list string and returns an array of `RouterTableEntry` objects""" 1410*cfb92d14SAndroid Build Coastguard Worker return [RouterTableEntry(item) for item in router_table_list.split('\n')[1:-1]] 1411*cfb92d14SAndroid Build Coastguard Worker 1412*cfb92d14SAndroid Build Coastguard Worker 1413*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1414*cfb92d14SAndroid Build Coastguard Worker 1415*cfb92d14SAndroid Build Coastguard Worker 1416*cfb92d14SAndroid Build Coastguard Workerclass AddressCacheEntry(object): 1417*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates an address cache entry""" 1418*cfb92d14SAndroid Build Coastguard Worker 1419*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1420*cfb92d14SAndroid Build Coastguard Worker 1421*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1422*cfb92d14SAndroid Build Coastguard Worker # 1423*cfb92d14SAndroid Build Coastguard Worker # '\t"fd00:1234::100:8 -> 0xfffe, Age:1, State:query, CanEvict:no, Timeout:3, RetryDelay:15"` 1424*cfb92d14SAndroid Build Coastguard Worker # '\t"fd00:1234::3:2 -> 0x2000, Age:0, State:cached, LastTrans:0, ML-EID:fd40:ea58:a88c:0:b7ab:4919:aa7b:11a3"` 1425*cfb92d14SAndroid Build Coastguard Worker 1426*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1427*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1428*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1429*cfb92d14SAndroid Build Coastguard Worker 1430*cfb92d14SAndroid Build Coastguard Worker # First item in the extended address 1431*cfb92d14SAndroid Build Coastguard Worker self._address = items[0] 1432*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = int(items[2], 16) 1433*cfb92d14SAndroid Build Coastguard Worker 1434*cfb92d14SAndroid Build Coastguard Worker # Convert the rest into a dictionary by splitting the text using ':' as 1435*cfb92d14SAndroid Build Coastguard Worker # separator 1436*cfb92d14SAndroid Build Coastguard Worker dict = {item.split(':')[0]: item.split(':')[1] for item in items[3:]} 1437*cfb92d14SAndroid Build Coastguard Worker 1438*cfb92d14SAndroid Build Coastguard Worker self._age = int(dict['Age'], 0) 1439*cfb92d14SAndroid Build Coastguard Worker 1440*cfb92d14SAndroid Build Coastguard Worker self._state = dict['State'] 1441*cfb92d14SAndroid Build Coastguard Worker 1442*cfb92d14SAndroid Build Coastguard Worker if self._state == ADDRESS_CACHE_ENTRY_STATE_CACHED: 1443*cfb92d14SAndroid Build Coastguard Worker self._last_trans = int(dict.get("LastTrans", "-1"), 0) 1444*cfb92d14SAndroid Build Coastguard Worker else: 1445*cfb92d14SAndroid Build Coastguard Worker self._can_evict = (dict['CanEvict'] == 'yes') 1446*cfb92d14SAndroid Build Coastguard Worker self._timeout = int(dict['Timeout']) 1447*cfb92d14SAndroid Build Coastguard Worker self._retry_delay = int(dict['RetryDelay']) 1448*cfb92d14SAndroid Build Coastguard Worker 1449*cfb92d14SAndroid Build Coastguard Worker @property 1450*cfb92d14SAndroid Build Coastguard Worker def address(self): 1451*cfb92d14SAndroid Build Coastguard Worker return self._address 1452*cfb92d14SAndroid Build Coastguard Worker 1453*cfb92d14SAndroid Build Coastguard Worker @property 1454*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1455*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1456*cfb92d14SAndroid Build Coastguard Worker 1457*cfb92d14SAndroid Build Coastguard Worker @property 1458*cfb92d14SAndroid Build Coastguard Worker def age(self): 1459*cfb92d14SAndroid Build Coastguard Worker return self._age 1460*cfb92d14SAndroid Build Coastguard Worker 1461*cfb92d14SAndroid Build Coastguard Worker @property 1462*cfb92d14SAndroid Build Coastguard Worker def state(self): 1463*cfb92d14SAndroid Build Coastguard Worker return self._state 1464*cfb92d14SAndroid Build Coastguard Worker 1465*cfb92d14SAndroid Build Coastguard Worker def can_evict(self): 1466*cfb92d14SAndroid Build Coastguard Worker return self._can_evict 1467*cfb92d14SAndroid Build Coastguard Worker 1468*cfb92d14SAndroid Build Coastguard Worker @property 1469*cfb92d14SAndroid Build Coastguard Worker def timeout(self): 1470*cfb92d14SAndroid Build Coastguard Worker return self._timeout 1471*cfb92d14SAndroid Build Coastguard Worker 1472*cfb92d14SAndroid Build Coastguard Worker @property 1473*cfb92d14SAndroid Build Coastguard Worker def retry_delay(self): 1474*cfb92d14SAndroid Build Coastguard Worker return self._retry_delay 1475*cfb92d14SAndroid Build Coastguard Worker 1476*cfb92d14SAndroid Build Coastguard Worker @property 1477*cfb92d14SAndroid Build Coastguard Worker def last_trans(self): 1478*cfb92d14SAndroid Build Coastguard Worker return self._last_trans 1479*cfb92d14SAndroid Build Coastguard Worker 1480*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1481*cfb92d14SAndroid Build Coastguard Worker return 'AddressCacheEntry({})'.format(self.__dict__) 1482*cfb92d14SAndroid Build Coastguard Worker 1483*cfb92d14SAndroid Build Coastguard Worker 1484*cfb92d14SAndroid Build Coastguard Workerdef parse_address_cache_table_result(addr_cache_table_list): 1485*cfb92d14SAndroid Build Coastguard Worker """ Parses address cache table list string and returns an array of `AddressCacheEntry` objects""" 1486*cfb92d14SAndroid Build Coastguard Worker return [AddressCacheEntry(item) for item in addr_cache_table_list.split('\n')[1:-1]] 1487*cfb92d14SAndroid Build Coastguard Worker 1488*cfb92d14SAndroid Build Coastguard Worker 1489*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1490*cfb92d14SAndroid Build Coastguard Worker 1491*cfb92d14SAndroid Build Coastguard Worker 1492*cfb92d14SAndroid Build Coastguard Workerclass InterfaceRoute(object): 1493*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates an interface route entry""" 1494*cfb92d14SAndroid Build Coastguard Worker 1495*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1496*cfb92d14SAndroid Build Coastguard Worker 1497*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1498*cfb92d14SAndroid Build Coastguard Worker # 1499*cfb92d14SAndroid Build Coastguard Worker # '\t"fd00:abba::/64 metric:256 "' 1500*cfb92d14SAndroid Build Coastguard Worker # 1501*cfb92d14SAndroid Build Coastguard Worker 1502*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1503*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1504*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1505*cfb92d14SAndroid Build Coastguard Worker 1506*cfb92d14SAndroid Build Coastguard Worker # First item in the extended address 1507*cfb92d14SAndroid Build Coastguard Worker self._route_prefix = items[0].split('/')[0] 1508*cfb92d14SAndroid Build Coastguard Worker self._prefix_len = int(items[0].split('/')[1], 0) 1509*cfb92d14SAndroid Build Coastguard Worker self._metric = int(items[1].split(':')[1], 0) 1510*cfb92d14SAndroid Build Coastguard Worker 1511*cfb92d14SAndroid Build Coastguard Worker @property 1512*cfb92d14SAndroid Build Coastguard Worker def route_prefix(self): 1513*cfb92d14SAndroid Build Coastguard Worker return self._route_prefix 1514*cfb92d14SAndroid Build Coastguard Worker 1515*cfb92d14SAndroid Build Coastguard Worker @property 1516*cfb92d14SAndroid Build Coastguard Worker def prefix_len(self): 1517*cfb92d14SAndroid Build Coastguard Worker return self._prefix_len 1518*cfb92d14SAndroid Build Coastguard Worker 1519*cfb92d14SAndroid Build Coastguard Worker @property 1520*cfb92d14SAndroid Build Coastguard Worker def metric(self): 1521*cfb92d14SAndroid Build Coastguard Worker return self._metric 1522*cfb92d14SAndroid Build Coastguard Worker 1523*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1524*cfb92d14SAndroid Build Coastguard Worker return 'InterfaceRoute({})'.format(self.__dict__) 1525*cfb92d14SAndroid Build Coastguard Worker 1526*cfb92d14SAndroid Build Coastguard Worker 1527*cfb92d14SAndroid Build Coastguard Workerdef parse_interface_routes_result(interface_routes_list): 1528*cfb92d14SAndroid Build Coastguard Worker """ Parses interface routes list string and returns an array of `InterfaceRoute` objects""" 1529*cfb92d14SAndroid Build Coastguard Worker return [InterfaceRoute(item) for item in interface_routes_list.split('\n')[1:-1]] 1530*cfb92d14SAndroid Build Coastguard Worker 1531*cfb92d14SAndroid Build Coastguard Worker 1532*cfb92d14SAndroid Build Coastguard Worker# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1533*cfb92d14SAndroid Build Coastguard Worker 1534*cfb92d14SAndroid Build Coastguard Worker 1535*cfb92d14SAndroid Build Coastguard Workerclass MultiRadioEntry(object): 1536*cfb92d14SAndroid Build Coastguard Worker """ This object encapsulates a multi radio info entry""" 1537*cfb92d14SAndroid Build Coastguard Worker 1538*cfb92d14SAndroid Build Coastguard Worker def __init__(self, text): 1539*cfb92d14SAndroid Build Coastguard Worker 1540*cfb92d14SAndroid Build Coastguard Worker # Example of expected text: 1541*cfb92d14SAndroid Build Coastguard Worker # 1542*cfb92d14SAndroid Build Coastguard Worker # `\t"0EB758375B4976E7, RLOC16:f403, Radios:[IEEE_802_15_4(200), TREL_UDP6(255)]"` 1543*cfb92d14SAndroid Build Coastguard Worker # 1544*cfb92d14SAndroid Build Coastguard Worker 1545*cfb92d14SAndroid Build Coastguard Worker # We get rid of the first two chars `\t"' and last char '"', split the rest using whitespace as separator. 1546*cfb92d14SAndroid Build Coastguard Worker # Then remove any ',' at end of items in the list. 1547*cfb92d14SAndroid Build Coastguard Worker items = [item[:-1] if item[-1] == ',' else item for item in text[2:-1].split()] 1548*cfb92d14SAndroid Build Coastguard Worker 1549*cfb92d14SAndroid Build Coastguard Worker # First item is the extended address 1550*cfb92d14SAndroid Build Coastguard Worker self._ext_address = items[0] 1551*cfb92d14SAndroid Build Coastguard Worker 1552*cfb92d14SAndroid Build Coastguard Worker # Second items is 'RLCO16:{rloc}' 1553*cfb92d14SAndroid Build Coastguard Worker self._rloc16 = items[1].split(':')[1] 1554*cfb92d14SAndroid Build Coastguard Worker 1555*cfb92d14SAndroid Build Coastguard Worker # Join back rest of items, split using ":" to get list of radios of form "[IEEE_802_15_4(200) TREL_UDP6(255)]" 1556*cfb92d14SAndroid Build Coastguard Worker radios = " ".join(items[2:]).split(":")[1] 1557*cfb92d14SAndroid Build Coastguard Worker 1558*cfb92d14SAndroid Build Coastguard Worker if radios != "[]": 1559*cfb92d14SAndroid Build Coastguard Worker # Get rid of `[ and `]`, then split using " ", then convert to dictionary mapping radio type 1560*cfb92d14SAndroid Build Coastguard Worker # to its preference value. 1561*cfb92d14SAndroid Build Coastguard Worker self._radios = {radio.split("(")[0]: radio.split("(")[1][:-1] for radio in radios[1:-1].split(' ')} 1562*cfb92d14SAndroid Build Coastguard Worker else: 1563*cfb92d14SAndroid Build Coastguard Worker self._radios = {} 1564*cfb92d14SAndroid Build Coastguard Worker 1565*cfb92d14SAndroid Build Coastguard Worker @property 1566*cfb92d14SAndroid Build Coastguard Worker def ext_address(self): 1567*cfb92d14SAndroid Build Coastguard Worker return self._ext_address 1568*cfb92d14SAndroid Build Coastguard Worker 1569*cfb92d14SAndroid Build Coastguard Worker @property 1570*cfb92d14SAndroid Build Coastguard Worker def rloc16(self): 1571*cfb92d14SAndroid Build Coastguard Worker return self._rloc16 1572*cfb92d14SAndroid Build Coastguard Worker 1573*cfb92d14SAndroid Build Coastguard Worker @property 1574*cfb92d14SAndroid Build Coastguard Worker def radios(self): 1575*cfb92d14SAndroid Build Coastguard Worker return self._radios 1576*cfb92d14SAndroid Build Coastguard Worker 1577*cfb92d14SAndroid Build Coastguard Worker def supports(self, radio_type): 1578*cfb92d14SAndroid Build Coastguard Worker return radio_type in self._radios 1579*cfb92d14SAndroid Build Coastguard Worker 1580*cfb92d14SAndroid Build Coastguard Worker def preference(self, radio_type): 1581*cfb92d14SAndroid Build Coastguard Worker return int(self._radios[radio_type], 0) if self.supports(radio_type) else None 1582*cfb92d14SAndroid Build Coastguard Worker 1583*cfb92d14SAndroid Build Coastguard Worker def __repr__(self): 1584*cfb92d14SAndroid Build Coastguard Worker return 'MultiRadioEntry({})'.format(self.__dict__) 1585*cfb92d14SAndroid Build Coastguard Worker 1586*cfb92d14SAndroid Build Coastguard Worker 1587*cfb92d14SAndroid Build Coastguard Workerdef parse_multi_radio_result(multi_radio_list): 1588*cfb92d14SAndroid Build Coastguard Worker """ Parses multi radio neighbor list string and returns an array of `MultiRadioEntry` objects""" 1589*cfb92d14SAndroid Build Coastguard Worker return [MultiRadioEntry(item) for item in multi_radio_list.split('\n')[1:-1]] 1590