1 /*
2 * Copyright (c) 2016-2017, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "changed_props_set.hpp"
29
30 #include "common/code_utils.hpp"
31
32 namespace ot {
33 namespace Ncp {
34
35 static constexpr uint8_t kBitsPerByte = 8; ///< Number of bits in a byte.
36
37 // ----------------------------------------------------------------------------
38 // MARK: ChangedPropsSet class
39 // ----------------------------------------------------------------------------
40
41 // Defines the list of properties that can support unsolicited update.
42 //
43 // Note that {`SPINEL_PROP_LAST_STATUS`, `SPINEL_STATUS_RESET_UNKNOWN`} should be first entry to ensure that RESET is
44 // reported before any other property update.
45 //
46 // Since a `uint64_t` is used as bit-mask to track which entries are in the changed set, we should ensure that the
47 // number of entries in the list is always less than or equal to 64.
48 //
49 const ChangedPropsSet::Entry ChangedPropsSet::mSupportedProps[] = {
50 // Spinel property , Status (if prop is `LAST_STATUS`), IsFilterable?
51
52 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_RESET_UNKNOWN, false},
53 {SPINEL_PROP_STREAM_DEBUG, SPINEL_STATUS_OK, true},
54 {SPINEL_PROP_IPV6_LL_ADDR, SPINEL_STATUS_OK, true},
55 {SPINEL_PROP_IPV6_ML_ADDR, SPINEL_STATUS_OK, true},
56 {SPINEL_PROP_IPV6_ADDRESS_TABLE, SPINEL_STATUS_OK, true},
57 {SPINEL_PROP_NET_ROLE, SPINEL_STATUS_OK, true},
58 {SPINEL_PROP_NET_PARTITION_ID, SPINEL_STATUS_OK, true},
59 {SPINEL_PROP_NET_KEY_SEQUENCE_COUNTER, SPINEL_STATUS_OK, true},
60 {SPINEL_PROP_THREAD_LEADER_NETWORK_DATA, SPINEL_STATUS_OK, true},
61 {SPINEL_PROP_THREAD_CHILD_TABLE, SPINEL_STATUS_OK, true},
62 {SPINEL_PROP_THREAD_ON_MESH_NETS, SPINEL_STATUS_OK, true},
63 {SPINEL_PROP_THREAD_OFF_MESH_ROUTES, SPINEL_STATUS_OK, true},
64 {SPINEL_PROP_NET_STACK_UP, SPINEL_STATUS_OK, true},
65 {SPINEL_PROP_NET_REQUIRE_JOIN_EXISTING, SPINEL_STATUS_OK, true},
66 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_NOMEM, true},
67 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_DROPPED, true},
68 #if OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE
69 {SPINEL_PROP_JAM_DETECTED, SPINEL_STATUS_OK, true},
70 #endif
71 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_FAILURE, false},
72 {SPINEL_PROP_MAC_SCAN_STATE, SPINEL_STATUS_OK, false},
73 {SPINEL_PROP_IPV6_MULTICAST_ADDRESS_TABLE, SPINEL_STATUS_OK, true},
74 {SPINEL_PROP_PHY_CHAN, SPINEL_STATUS_OK, true},
75 {SPINEL_PROP_MAC_15_4_PANID, SPINEL_STATUS_OK, true},
76 {SPINEL_PROP_NET_NETWORK_NAME, SPINEL_STATUS_OK, true},
77 {SPINEL_PROP_NET_XPANID, SPINEL_STATUS_OK, true},
78 {SPINEL_PROP_NET_NETWORK_KEY, SPINEL_STATUS_OK, true},
79 {SPINEL_PROP_NET_PSKC, SPINEL_STATUS_OK, true},
80 {SPINEL_PROP_NET_LEAVE_GRACEFULLY, SPINEL_STATUS_OK, false},
81 {SPINEL_PROP_PHY_CHAN_SUPPORTED, SPINEL_STATUS_OK, true},
82 #if OPENTHREAD_CONFIG_CHANNEL_MANAGER_ENABLE
83 {SPINEL_PROP_CHANNEL_MANAGER_NEW_CHANNEL, SPINEL_STATUS_OK, true},
84 #endif
85 #if OPENTHREAD_CONFIG_JOINER_ENABLE
86 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_NO_PEERS, false},
87 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_SECURITY, false},
88 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_RSP_TIMEOUT, false},
89 {SPINEL_PROP_LAST_STATUS, SPINEL_STATUS_JOIN_SUCCESS, false},
90 #endif
91 #if OPENTHREAD_CONFIG_TIME_SYNC_ENABLE
92 {SPINEL_PROP_THREAD_NETWORK_TIME, SPINEL_STATUS_OK, false},
93 #endif
94 {SPINEL_PROP_PARENT_RESPONSE_INFO, SPINEL_STATUS_OK, true},
95 {SPINEL_PROP_THREAD_MGMT_SET_PENDING_DATASET_TLVS, SPINEL_STATUS_OK, false},
96 };
97
GetNumEntries(void) const98 uint8_t ChangedPropsSet::GetNumEntries(void) const
99 {
100 static_assert(OT_ARRAY_LENGTH(mSupportedProps) <= sizeof(mChangedSet) * kBitsPerByte,
101 "Changed set size is smaller than number of entries in `mSupportedProps[]` array");
102
103 return OT_ARRAY_LENGTH(mSupportedProps);
104 }
105
Add(spinel_prop_key_t aPropKey,spinel_status_t aStatus)106 void ChangedPropsSet::Add(spinel_prop_key_t aPropKey, spinel_status_t aStatus)
107 {
108 uint8_t numEntries;
109 const Entry *entry;
110
111 entry = GetSupportedEntries(numEntries);
112
113 for (uint8_t index = 0; index < numEntries; index++, entry++)
114 {
115 if ((entry->mPropKey == aPropKey) && (entry->mStatus == aStatus))
116 {
117 if (!IsEntryFiltered(index))
118 {
119 SetBit(mChangedSet, index);
120 }
121
122 break;
123 }
124 }
125 }
126
EnablePropertyFilter(spinel_prop_key_t aPropKey,bool aEnable)127 otError ChangedPropsSet::EnablePropertyFilter(spinel_prop_key_t aPropKey, bool aEnable)
128 {
129 uint8_t numEntries;
130 const Entry *entry;
131 bool didFind = false;
132
133 entry = GetSupportedEntries(numEntries);
134
135 for (uint8_t index = 0; index < numEntries; index++, entry++)
136 {
137 if (entry->mFilterable && (entry->mPropKey == aPropKey))
138 {
139 if (aEnable)
140 {
141 SetBit(mFilterSet, index);
142
143 // If filter is enabled for a property, the `mChangedSet` is cleared
144 // for the same property so to ensure a pending update is also filtered.
145
146 ClearBit(mChangedSet, index);
147 }
148 else
149 {
150 ClearBit(mFilterSet, index);
151 }
152
153 didFind = true;
154
155 // Continue the search only if the prop key is `LAST_STATUS`, as
156 // we have multiple filterable `LAST_STATUS` entries in the table
157 // with different error status (DROPPED and NOMEM).
158
159 if (aPropKey != SPINEL_PROP_LAST_STATUS)
160 {
161 break;
162 }
163 }
164 }
165
166 return didFind ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS;
167 }
168
IsPropertyFiltered(spinel_prop_key_t aPropKey) const169 bool ChangedPropsSet::IsPropertyFiltered(spinel_prop_key_t aPropKey) const
170 {
171 bool isFiltered = false;
172 uint8_t numEntries;
173 const Entry *entry;
174
175 entry = GetSupportedEntries(numEntries);
176
177 for (uint8_t index = 0; index < numEntries; index++, entry++)
178 {
179 if (entry->mFilterable && (entry->mPropKey == aPropKey))
180 {
181 isFiltered = IsEntryFiltered(index);
182
183 break;
184 }
185 }
186
187 return isFiltered;
188 }
189
190 } // namespace Ncp
191 } // namespace ot
192