/src/wpantund/src/ncp-spinel/SpinelNCPTaskGetNetworkTopology.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2016 Nest Labs, Inc. |
4 | | * All rights reserved. |
5 | | * |
6 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | * you may not use this file except in compliance with the License. |
8 | | * You may obtain a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, software |
13 | | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | * See the License for the specific language governing permissions and |
16 | | * limitations under the License. |
17 | | * |
18 | | */ |
19 | | |
20 | | #if HAVE_CONFIG_H |
21 | | #include <config.h> |
22 | | #endif |
23 | | |
24 | | #include "assert-macros.h" |
25 | | #include <syslog.h> |
26 | | #include <errno.h> |
27 | | #include "SpinelNCPTaskGetNetworkTopology.h" |
28 | | #include "SpinelNCPInstance.h" |
29 | | #include "spinel-extra.h" |
30 | | |
31 | | using namespace nl; |
32 | | using namespace nl::wpantund; |
33 | | |
34 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::TableEntry::TableEntry(void) |
35 | 3.62k | { |
36 | 3.62k | clear(); |
37 | 3.62k | } |
38 | | |
39 | | void |
40 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::TableEntry::clear(void) |
41 | 6.42k | { |
42 | 6.42k | memset(mExtAddress, 0, sizeof(mExtAddress)); |
43 | 6.42k | mRloc16 = 0; |
44 | 6.42k | mAge = 0; |
45 | 6.42k | mLinkQualityIn = 0; |
46 | 6.42k | mAverageRssi = 0; |
47 | 6.42k | mLastRssi = 0; |
48 | 6.42k | mRxOnWhenIdle = false; |
49 | 6.42k | mSecureDataRequest = false; |
50 | 6.42k | mFullFunction = false; |
51 | 6.42k | mFullNetworkData = false; |
52 | 6.42k | mTimeout = 0; |
53 | 6.42k | mNetworkDataVersion = 0; |
54 | 6.42k | mLinkFrameCounter = 0; |
55 | 6.42k | mMleFrameCounter = 0; |
56 | 6.42k | mIsChild = false; |
57 | 6.42k | mRouterId = 0; |
58 | 6.42k | mNextHop = 0; |
59 | 6.42k | mPathCost = 0; |
60 | 6.42k | mLinkQualityOut = 0; |
61 | 6.42k | mLinkEstablished = false; |
62 | 6.42k | mIPv6Addresses.clear(); |
63 | 6.42k | mFrameErrorRate = 0; |
64 | 6.42k | mMessageErrorRate = 0; |
65 | 6.42k | } |
66 | | |
67 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::SpinelNCPTaskGetNetworkTopology( |
68 | | SpinelNCPInstance* instance, |
69 | | CallbackWithStatusArg1 cb, |
70 | | Type table_type, |
71 | | ResultFormat result_format |
72 | 0 | ) : SpinelNCPTask(instance, cb), mType(table_type), mTable(), mResultFormat(result_format) |
73 | 0 | { |
74 | 0 | } |
75 | | |
76 | | int |
77 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_table( |
78 | | Type type, |
79 | | const uint8_t *data_in, |
80 | | spinel_size_t data_len, |
81 | | Table& table |
82 | 2.10k | ) { |
83 | 2.10k | int ret = kWPANTUNDStatus_Ok; |
84 | | |
85 | 2.10k | table.clear(); |
86 | | |
87 | 2.82k | while (data_len > 0) { |
88 | 2.42k | spinel_ssize_t len = 0; |
89 | 2.42k | const uint8_t *struct_data; |
90 | 2.42k | spinel_size_t struct_len; |
91 | 2.42k | TableEntry entry; |
92 | | |
93 | 2.42k | len = spinel_datatype_unpack( |
94 | 2.42k | data_in, |
95 | 2.42k | data_len, |
96 | 2.42k | SPINEL_DATATYPE_DATA_WLEN_S, |
97 | 2.42k | &struct_data, |
98 | 2.42k | &struct_len |
99 | 2.42k | ); |
100 | | |
101 | 2.42k | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
102 | | |
103 | 1.60k | switch (type) |
104 | 1.60k | { |
105 | 257 | case kChildTable: |
106 | 257 | ret = parse_child_entry(struct_data, struct_len, entry); |
107 | 257 | break; |
108 | | |
109 | 0 | case kChildTableAddresses: |
110 | 0 | ret = parse_child_addresses_entry(struct_data, struct_len, entry); |
111 | 0 | break; |
112 | | |
113 | 516 | case kNeighborTable: |
114 | 516 | ret = parse_neighbor_entry(struct_data, struct_len, entry); |
115 | 516 | break; |
116 | | |
117 | 236 | case kNeighborTableErrorRates: |
118 | 236 | ret = parse_neighbor_error_rates_entry(struct_data, struct_len, entry); |
119 | 236 | break; |
120 | | |
121 | 594 | case kRouterTable: |
122 | 594 | ret = parse_router_entry(struct_data, struct_len, entry); |
123 | 594 | break; |
124 | 1.60k | } |
125 | | |
126 | 1.60k | require_noerr(ret, bail); |
127 | | |
128 | 716 | table.push_back(entry); |
129 | | |
130 | 716 | data_in += len; |
131 | 716 | data_len -= len; |
132 | 716 | } |
133 | | |
134 | 2.10k | bail: |
135 | 2.10k | return ret; |
136 | 2.10k | } |
137 | | |
138 | | int |
139 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_child_table( |
140 | | const uint8_t *data_in, |
141 | | spinel_size_t data_len, |
142 | | Table& child_table |
143 | 807 | ) { |
144 | 807 | return parse_table(kChildTable, data_in, data_len, child_table); |
145 | 807 | } |
146 | | |
147 | | int |
148 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_child_addresses_table( |
149 | | const uint8_t *data_in, |
150 | | spinel_size_t data_len, |
151 | | Table& child_addr_table |
152 | 0 | ) { |
153 | 0 | return parse_table(kChildTableAddresses, data_in, data_len, child_addr_table); |
154 | 0 | } |
155 | | |
156 | | int |
157 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_neighbor_table( |
158 | | const uint8_t *data_in, |
159 | | spinel_size_t data_len, |
160 | | Table& neighbor_table |
161 | 485 | ) { |
162 | 485 | return parse_table(kNeighborTable, data_in, data_len, neighbor_table); |
163 | 485 | } |
164 | | |
165 | | int |
166 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::prase_neighbor_error_rates_table( |
167 | | const uint8_t *data_in, |
168 | | spinel_size_t data_len, |
169 | | Table& neighbor_err_rate_table |
170 | 207 | ) { |
171 | 207 | return parse_table(kNeighborTableErrorRates, data_in, data_len, neighbor_err_rate_table); |
172 | 207 | } |
173 | | |
174 | | int |
175 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_router_table( |
176 | | const uint8_t *data_in, |
177 | | spinel_size_t data_len, |
178 | | Table& router_table |
179 | 608 | ) { |
180 | 608 | return parse_table(kRouterTable, data_in, data_len, router_table); |
181 | 608 | } |
182 | | |
183 | | int |
184 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_child_entry( |
185 | | const uint8_t *data_in, |
186 | | spinel_size_t data_len, |
187 | | TableEntry& child_info |
188 | 844 | ) { |
189 | 844 | int ret = kWPANTUNDStatus_Ok; |
190 | 844 | spinel_ssize_t len = 0; |
191 | 844 | const spinel_eui64_t *eui64 = NULL; |
192 | 844 | uint8_t mode; |
193 | | |
194 | 844 | child_info.clear(); |
195 | 844 | child_info.mType = kChildTable; |
196 | | |
197 | 844 | len = spinel_datatype_unpack( |
198 | 844 | data_in, |
199 | 844 | data_len, |
200 | 844 | ( |
201 | 844 | SPINEL_DATATYPE_EUI64_S // EUI64 Address |
202 | | SPINEL_DATATYPE_UINT16_S // Rloc16 |
203 | | SPINEL_DATATYPE_UINT32_S // Timeout |
204 | | SPINEL_DATATYPE_UINT32_S // Age |
205 | | SPINEL_DATATYPE_UINT8_S // Network Data Version |
206 | | SPINEL_DATATYPE_UINT8_S // Link Quality In |
207 | | SPINEL_DATATYPE_INT8_S // Average RSS |
208 | | SPINEL_DATATYPE_UINT8_S // Mode (flags) |
209 | 844 | SPINEL_DATATYPE_INT8_S // Last Rssi |
210 | 844 | ), |
211 | 844 | &eui64, |
212 | 844 | &child_info.mRloc16, |
213 | 844 | &child_info.mTimeout, |
214 | 844 | &child_info.mAge, |
215 | 844 | &child_info.mNetworkDataVersion, |
216 | 844 | &child_info.mLinkQualityIn, |
217 | 844 | &child_info.mAverageRssi, |
218 | 844 | &mode, |
219 | 844 | &child_info.mLastRssi |
220 | 844 | ); |
221 | | |
222 | 844 | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
223 | | |
224 | 316 | memcpy(child_info.mExtAddress, eui64, sizeof(child_info.mExtAddress)); |
225 | | |
226 | 316 | child_info.mRxOnWhenIdle = ((mode & kThreadMode_RxOnWhenIdle) != 0); |
227 | 316 | child_info.mSecureDataRequest = ((mode & kThreadMode_SecureDataRequest) != 0); |
228 | 316 | child_info.mFullFunction = ((mode & kThreadMode_FullFunctionDevice) != 0); |
229 | 316 | child_info.mFullNetworkData = ((mode & kThreadMode_FullNetworkData) != 0); |
230 | | |
231 | 844 | bail: |
232 | 844 | return ret; |
233 | 316 | } |
234 | | |
235 | | int |
236 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_child_addresses_entry( |
237 | | const uint8_t *data_in, |
238 | | spinel_size_t data_len, |
239 | | TableEntry& child_addr_info |
240 | 0 | ) { |
241 | 0 | int ret = kWPANTUNDStatus_Ok; |
242 | 0 | spinel_ssize_t len = 0; |
243 | 0 | const spinel_eui64_t *eui64 = NULL; |
244 | 0 | struct in6_addr *ip6_addr = NULL; |
245 | |
|
246 | 0 | child_addr_info.clear(); |
247 | 0 | child_addr_info.mType = kChildTableAddresses; |
248 | |
|
249 | 0 | len = spinel_datatype_unpack( |
250 | 0 | data_in, |
251 | 0 | data_len, |
252 | 0 | ( |
253 | 0 | SPINEL_DATATYPE_EUI64_S // EUI64 Address |
254 | 0 | SPINEL_DATATYPE_UINT16_S // Rloc16 |
255 | 0 | ), |
256 | 0 | &eui64, |
257 | 0 | &child_addr_info.mRloc16 |
258 | 0 | ); |
259 | |
|
260 | 0 | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
261 | | |
262 | 0 | memcpy(child_addr_info.mExtAddress, eui64, sizeof(child_addr_info.mExtAddress)); |
263 | |
|
264 | 0 | data_in += len; |
265 | 0 | data_len -= len; |
266 | |
|
267 | 0 | while (data_len > 0) { |
268 | 0 | len = spinel_datatype_unpack( |
269 | 0 | data_in, |
270 | 0 | data_len, |
271 | 0 | SPINEL_DATATYPE_IPv6ADDR_S, |
272 | 0 | &ip6_addr |
273 | 0 | ); |
274 | |
|
275 | 0 | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
276 | | |
277 | 0 | child_addr_info.mIPv6Addresses.push_back(*ip6_addr); |
278 | |
|
279 | 0 | data_in += len; |
280 | 0 | data_len -= len; |
281 | 0 | } |
282 | | |
283 | 0 | bail: |
284 | 0 | return ret; |
285 | 0 | } |
286 | | |
287 | | int |
288 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_neighbor_entry( |
289 | | const uint8_t *data_in, |
290 | | spinel_size_t data_len, |
291 | | TableEntry& neighbor_info |
292 | 1.12k | ) { |
293 | 1.12k | int ret = kWPANTUNDStatus_Ok; |
294 | 1.12k | spinel_ssize_t len = 0; |
295 | 1.12k | const spinel_eui64_t *eui64 = NULL; |
296 | 1.12k | uint8_t mode; |
297 | 1.12k | bool is_child = false; |
298 | | |
299 | 1.12k | neighbor_info.clear(); |
300 | 1.12k | neighbor_info.mType = kNeighborTable; |
301 | | |
302 | 1.12k | len = spinel_datatype_unpack( |
303 | 1.12k | data_in, |
304 | 1.12k | data_len, |
305 | 1.12k | ( |
306 | 1.12k | SPINEL_DATATYPE_EUI64_S // EUI64 Address |
307 | | SPINEL_DATATYPE_UINT16_S // Rloc16 |
308 | | SPINEL_DATATYPE_UINT32_S // Age |
309 | | SPINEL_DATATYPE_UINT8_S // Link Quality In |
310 | | SPINEL_DATATYPE_INT8_S // Average RSS |
311 | | SPINEL_DATATYPE_UINT8_S // Mode (flags) |
312 | | SPINEL_DATATYPE_BOOL_S // Is Child |
313 | | SPINEL_DATATYPE_UINT32_S // Link Frame Counter |
314 | | SPINEL_DATATYPE_UINT32_S // MLE Frame Counter |
315 | 1.12k | SPINEL_DATATYPE_INT8_S // Last Rssi |
316 | 1.12k | ), |
317 | 1.12k | &eui64, |
318 | 1.12k | &neighbor_info.mRloc16, |
319 | 1.12k | &neighbor_info.mAge, |
320 | 1.12k | &neighbor_info.mLinkQualityIn, |
321 | 1.12k | &neighbor_info.mAverageRssi, |
322 | 1.12k | &mode, |
323 | 1.12k | &is_child, |
324 | 1.12k | &neighbor_info.mLinkFrameCounter, |
325 | 1.12k | &neighbor_info.mMleFrameCounter, |
326 | 1.12k | &neighbor_info.mLastRssi |
327 | 1.12k | ); |
328 | | |
329 | 1.12k | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
330 | | |
331 | 307 | memcpy(neighbor_info.mExtAddress, eui64, sizeof(neighbor_info.mExtAddress)); |
332 | | |
333 | 307 | neighbor_info.mRxOnWhenIdle = ((mode & kThreadMode_RxOnWhenIdle) != 0); |
334 | 307 | neighbor_info.mSecureDataRequest = ((mode & kThreadMode_SecureDataRequest) != 0); |
335 | 307 | neighbor_info.mFullFunction = ((mode & kThreadMode_FullFunctionDevice) != 0); |
336 | 307 | neighbor_info.mFullNetworkData = ((mode & kThreadMode_FullNetworkData) != 0); |
337 | 307 | neighbor_info.mIsChild = is_child; |
338 | | |
339 | 1.12k | bail: |
340 | 1.12k | return ret; |
341 | 307 | } |
342 | | |
343 | | int |
344 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_neighbor_error_rates_entry( |
345 | | const uint8_t *data_in, |
346 | | spinel_size_t data_len, |
347 | | TableEntry& neighbor_err_rates_info |
348 | 236 | ) { |
349 | 236 | int ret = kWPANTUNDStatus_Ok; |
350 | 236 | spinel_ssize_t len = 0; |
351 | 236 | const spinel_eui64_t *eui64 = NULL; |
352 | | |
353 | 236 | neighbor_err_rates_info.clear(); |
354 | 236 | neighbor_err_rates_info.mType = kNeighborTableErrorRates; |
355 | | |
356 | 236 | len = spinel_datatype_unpack( |
357 | 236 | data_in, |
358 | 236 | data_len, |
359 | 236 | ( |
360 | 236 | SPINEL_DATATYPE_EUI64_S // EUI64 Address |
361 | | SPINEL_DATATYPE_UINT16_S // Rloc16 |
362 | | SPINEL_DATATYPE_UINT16_S // Frame Error Rate (0->0%, 0xffff->100%) |
363 | | SPINEL_DATATYPE_UINT16_S // Message Error Rate (0->0%, 0xffff->100%) |
364 | | SPINEL_DATATYPE_INT8_S // Average RSS |
365 | 236 | SPINEL_DATATYPE_INT8_S // Last Rssi |
366 | 236 | ), |
367 | 236 | &eui64, |
368 | 236 | &neighbor_err_rates_info.mRloc16, |
369 | 236 | &neighbor_err_rates_info.mFrameErrorRate, |
370 | 236 | &neighbor_err_rates_info.mMessageErrorRate, |
371 | 236 | &neighbor_err_rates_info.mAverageRssi, |
372 | 236 | &neighbor_err_rates_info.mLastRssi |
373 | 236 | ); |
374 | | |
375 | 236 | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
376 | | |
377 | 160 | memcpy(neighbor_err_rates_info.mExtAddress, eui64, sizeof(neighbor_err_rates_info.mExtAddress)); |
378 | | |
379 | 236 | bail: |
380 | 236 | return ret; |
381 | 160 | } |
382 | | |
383 | | int |
384 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::parse_router_entry( |
385 | | const uint8_t *data_in, |
386 | | spinel_size_t data_len, |
387 | | TableEntry& router_info |
388 | 594 | ) { |
389 | 594 | int ret = kWPANTUNDStatus_Ok; |
390 | 594 | spinel_ssize_t len = 0; |
391 | 594 | const spinel_eui64_t *eui64 = NULL; |
392 | 594 | uint8_t age; |
393 | 594 | bool link_established = false; |
394 | | |
395 | 594 | router_info.clear(); |
396 | 594 | router_info.mType = kRouterTable; |
397 | | |
398 | 594 | len = spinel_datatype_unpack( |
399 | 594 | data_in, |
400 | 594 | data_len, |
401 | 594 | ( |
402 | 594 | SPINEL_DATATYPE_EUI64_S // EUI64 Address |
403 | | SPINEL_DATATYPE_UINT16_S // Rloc16 |
404 | | SPINEL_DATATYPE_UINT8_S // Router Id |
405 | | SPINEL_DATATYPE_UINT8_S // Next hop |
406 | | SPINEL_DATATYPE_UINT8_S // Path Cost |
407 | | SPINEL_DATATYPE_UINT8_S // Link Quality In |
408 | | SPINEL_DATATYPE_UINT8_S // Link Quality Out |
409 | | SPINEL_DATATYPE_UINT8_S // Age |
410 | 594 | SPINEL_DATATYPE_BOOL_S // Is Link Established |
411 | 594 | ), |
412 | 594 | &eui64, |
413 | 594 | &router_info.mRloc16, |
414 | 594 | &router_info.mRouterId, |
415 | 594 | &router_info.mNextHop, |
416 | 594 | &router_info.mPathCost, |
417 | 594 | &router_info.mLinkQualityIn, |
418 | 594 | &router_info.mLinkQualityOut, |
419 | 594 | &age, |
420 | 594 | &link_established |
421 | 594 | ); |
422 | | |
423 | 594 | require_action(len > 0, bail, ret = kWPANTUNDStatus_Failure); |
424 | | |
425 | 220 | memcpy(router_info.mExtAddress, eui64, sizeof(router_info.mExtAddress)); |
426 | | |
427 | 220 | router_info.mAge = age; |
428 | 220 | router_info.mLinkEstablished = link_established; |
429 | | |
430 | 594 | bail: |
431 | 594 | return ret; |
432 | 220 | } |
433 | | |
434 | | unsigned int |
435 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::property_key_for_type(Type type) |
436 | 0 | { |
437 | 0 | unsigned int prop_key = 0; |
438 | |
|
439 | 0 | switch (type) |
440 | 0 | { |
441 | 0 | case kChildTable: |
442 | 0 | prop_key = SPINEL_PROP_THREAD_CHILD_TABLE; |
443 | 0 | break; |
444 | | |
445 | 0 | case kChildTableAddresses: |
446 | 0 | prop_key = SPINEL_PROP_THREAD_CHILD_TABLE_ADDRESSES; |
447 | 0 | break; |
448 | | |
449 | 0 | case kNeighborTable: |
450 | 0 | prop_key = SPINEL_PROP_THREAD_NEIGHBOR_TABLE; |
451 | 0 | break; |
452 | | |
453 | 0 | case kRouterTable: |
454 | 0 | prop_key = SPINEL_PROP_THREAD_ROUTER_TABLE; |
455 | 0 | break; |
456 | | |
457 | 0 | case kNeighborTableErrorRates: |
458 | 0 | prop_key = SPINEL_PROP_THREAD_NEIGHBOR_TABLE_ERROR_RATES; |
459 | 0 | break; |
460 | 0 | } |
461 | | |
462 | 0 | return prop_key; |
463 | 0 | } |
464 | | |
465 | | int |
466 | | nl::wpantund::SpinelNCPTaskGetNetworkTopology::vprocess_event(int event, va_list args) |
467 | 0 | { |
468 | 0 | int ret = kWPANTUNDStatus_Failure; |
469 | 0 | unsigned int prop_key; |
470 | 0 | const uint8_t *data_in; |
471 | 0 | spinel_size_t data_len; |
472 | |
|
473 | 0 | EH_BEGIN(); |
474 | |
|
475 | 0 | if (!mInstance->mEnabled) { |
476 | 0 | ret = kWPANTUNDStatus_InvalidWhenDisabled; |
477 | 0 | finish(ret); |
478 | 0 | EH_EXIT(); |
479 | 0 | } |
480 | | |
481 | 0 | if (mInstance->get_ncp_state() == UPGRADING) { |
482 | 0 | ret = kWPANTUNDStatus_InvalidForCurrentState; |
483 | 0 | finish(ret); |
484 | 0 | EH_EXIT(); |
485 | 0 | } |
486 | | |
487 | | // Wait for a bit to see if the NCP will enter the right state. |
488 | 0 | EH_REQUIRE_WITHIN( |
489 | 0 | NCP_DEFAULT_COMMAND_RESPONSE_TIMEOUT, |
490 | 0 | !ncp_state_is_initializing(mInstance->get_ncp_state()) && !mInstance->is_initializing_ncp(), |
491 | 0 | on_error |
492 | 0 | ); |
493 | | |
494 | | // The first event to a task is EVENT_STARTING_TASK. The following |
495 | | // line makes sure that we don't start processing this task |
496 | | // until it is properly scheduled. All tasks immediately receive |
497 | | // the initial `EVENT_STARTING_TASK` event, but further events |
498 | | // will only be received by that task once it is that task's turn |
499 | | // to execute. |
500 | 0 | EH_WAIT_UNTIL(EVENT_STARTING_TASK != event); |
501 | | |
502 | 0 | mNextCommand = SpinelPackData( |
503 | 0 | SPINEL_FRAME_PACK_CMD_PROP_VALUE_GET, |
504 | 0 | property_key_for_type(mType) |
505 | 0 | ); |
506 | |
|
507 | 0 | EH_SPAWN(&mSubPT, vprocess_send_command(event, args)); |
508 | | |
509 | 0 | ret = mNextCommandRet; |
510 | |
|
511 | 0 | require_noerr(ret, on_error); |
512 | | |
513 | 0 | require(EVENT_NCP_PROP_VALUE_IS == event, on_error); |
514 | | |
515 | 0 | prop_key = va_arg(args, unsigned int); |
516 | 0 | data_in = va_arg(args, const uint8_t*); |
517 | 0 | data_len = va_arg_small(args, spinel_size_t); |
518 | |
|
519 | 0 | require(prop_key == property_key_for_type(mType), on_error); |
520 | | |
521 | 0 | if (mType == kChildTable) { |
522 | 0 | parse_child_table(data_in, data_len, mTable); |
523 | 0 | } else if (mType == kChildTableAddresses) { |
524 | 0 | parse_child_addresses_table(data_in, data_len, mTable); |
525 | 0 | } else if (mType == kNeighborTable) { |
526 | 0 | parse_neighbor_table(data_in, data_len, mTable); |
527 | 0 | } else if (mType == kRouterTable) { |
528 | 0 | parse_router_table(data_in, data_len, mTable); |
529 | 0 | } else if (mType == kNeighborTableErrorRates) { |
530 | 0 | prase_neighbor_error_rates_table(data_in, data_len, mTable); |
531 | 0 | } |
532 | |
|
533 | 0 | ret = kWPANTUNDStatus_Ok; |
534 | |
|
535 | 0 | if (mResultFormat == kResultFormat_StringArray) |
536 | 0 | { |
537 | 0 | std::list<std::string> result; |
538 | 0 | Table::iterator it; |
539 | |
|
540 | 0 | for (it = mTable.begin(); it != mTable.end(); it++) |
541 | 0 | { |
542 | 0 | result.push_back(it->get_as_string()); |
543 | 0 | } |
544 | |
|
545 | 0 | finish(ret, result); |
546 | 0 | } |
547 | 0 | else if (mResultFormat == kResultFormat_ValueMapArray) |
548 | 0 | { |
549 | 0 | std::list<ValueMap> result; |
550 | 0 | Table::iterator it; |
551 | |
|
552 | 0 | for (it = mTable.begin(); it != mTable.end(); it++) |
553 | 0 | { |
554 | 0 | result.push_back(it->get_as_valuemap()); |
555 | 0 | } |
556 | |
|
557 | 0 | finish(ret, result); |
558 | 0 | } |
559 | 0 | else |
560 | 0 | { |
561 | 0 | finish(ret); |
562 | 0 | } |
563 | |
|
564 | 0 | mTable.clear(); |
565 | |
|
566 | 0 | EH_EXIT(); |
567 | | |
568 | 0 | on_error: |
569 | |
|
570 | 0 | if (ret == kWPANTUNDStatus_Ok) { |
571 | 0 | ret = kWPANTUNDStatus_Failure; |
572 | 0 | } |
573 | |
|
574 | 0 | syslog(LOG_ERR, "Getting child/neighbor table failed: %d", ret); |
575 | |
|
576 | 0 | finish(ret); |
577 | |
|
578 | 0 | mTable.clear(); |
579 | |
|
580 | 0 | EH_END(); |
581 | 0 | } |
582 | | |
583 | | std::string |
584 | | SpinelNCPTaskGetNetworkTopology::TableEntry::get_as_string(void) |
585 | 1.00k | { |
586 | 1.00k | char c_string[800]; |
587 | | |
588 | 1.00k | c_string[0] = 0; |
589 | | |
590 | 1.00k | switch (mType) |
591 | 1.00k | { |
592 | 316 | case kChildTable: |
593 | 316 | snprintf(c_string, sizeof(c_string), |
594 | 316 | "%02X%02X%02X%02X%02X%02X%02X%02X, " |
595 | 316 | "RLOC16:%04x, " |
596 | 316 | "NetDataVer:%d, " |
597 | 316 | "LQIn:%d, " |
598 | 316 | "AveRssi:%d, " |
599 | 316 | "LastRssi:%d, " |
600 | 316 | "Timeout:%u, " |
601 | 316 | "Age:%u, " |
602 | 316 | "RxOnIdle:%s, " |
603 | 316 | "FTD:%s, " |
604 | 316 | "SecDataReq:%s, " |
605 | 316 | "FullNetData:%s", |
606 | 316 | mExtAddress[0], mExtAddress[1], mExtAddress[2], mExtAddress[3], |
607 | 316 | mExtAddress[4], mExtAddress[5], mExtAddress[6], mExtAddress[7], |
608 | 316 | mRloc16, |
609 | 316 | mNetworkDataVersion, |
610 | 316 | mLinkQualityIn, |
611 | 316 | mAverageRssi, |
612 | 316 | mLastRssi, |
613 | 316 | mTimeout, |
614 | 316 | mAge, |
615 | 316 | mRxOnWhenIdle ? "yes" : "no", |
616 | 316 | mFullFunction ? "yes" : "no", |
617 | 316 | mSecureDataRequest ? "yes" : "no", |
618 | 316 | mFullNetworkData ? "yes" : "no" |
619 | 316 | ); |
620 | 316 | break; |
621 | | |
622 | 0 | case kChildTableAddresses: |
623 | 0 | { |
624 | 0 | char *str = c_string; |
625 | 0 | size_t remaning_len = sizeof(c_string); |
626 | 0 | int len; |
627 | 0 | bool is_first = true; |
628 | |
|
629 | 0 | len = snprintf(str, remaning_len, |
630 | 0 | "%02X%02X%02X%02X%02X%02X%02X%02X, RLOC16:%04x%s", |
631 | 0 | mExtAddress[0], mExtAddress[1], mExtAddress[2], mExtAddress[3], |
632 | 0 | mExtAddress[4], mExtAddress[5], mExtAddress[6], mExtAddress[7], |
633 | 0 | mRloc16, |
634 | 0 | mIPv6Addresses.size() > 0 ? ", IPv6Addrs:[" : "" |
635 | 0 | ); |
636 | |
|
637 | 0 | require(len >= 0 && len < remaning_len, bail); |
638 | 0 | str += len; |
639 | 0 | remaning_len -= len; |
640 | |
|
641 | 0 | for (std::list<struct in6_addr>::iterator it = mIPv6Addresses.begin(); it != mIPv6Addresses.end(); ++it) { |
642 | |
|
643 | 0 | len = snprintf( |
644 | 0 | str, remaning_len, |
645 | 0 | "%s%s", |
646 | 0 | is_first ? "" : ", ", |
647 | 0 | in6_addr_to_string(*it).c_str() |
648 | 0 | ); |
649 | |
|
650 | 0 | require(len >= 0 && len < remaning_len, bail); |
651 | 0 | str += len; |
652 | 0 | remaning_len -= len; |
653 | |
|
654 | 0 | is_first = false; |
655 | 0 | } |
656 | | |
657 | 0 | if (mIPv6Addresses.size() > 0) { |
658 | 0 | len = snprintf(str, remaning_len, "]"); |
659 | 0 | require(len >= 0 && len < remaning_len, bail); |
660 | 0 | str += len; |
661 | 0 | remaning_len -= len; |
662 | 0 | } |
663 | | |
664 | 0 | break; |
665 | 0 | } |
666 | | |
667 | 307 | case kNeighborTable: |
668 | 307 | snprintf(c_string, sizeof(c_string), |
669 | 307 | "%02X%02X%02X%02X%02X%02X%02X%02X, " |
670 | 307 | "RLOC16:%04x, " |
671 | 307 | "LQIn:%d, " |
672 | 307 | "AveRssi:%d, " |
673 | 307 | "LastRssi:%d, " |
674 | 307 | "Age:%u, " |
675 | 307 | "LinkFC:%u, " |
676 | 307 | "MleFC:%u, " |
677 | 307 | "IsChild:%s, " |
678 | 307 | "RxOnIdle:%s, " |
679 | 307 | "FTD:%s, " |
680 | 307 | "SecDataReq:%s, " |
681 | 307 | "FullNetData:%s", |
682 | 307 | mExtAddress[0], mExtAddress[1], mExtAddress[2], mExtAddress[3], |
683 | 307 | mExtAddress[4], mExtAddress[5], mExtAddress[6], mExtAddress[7], |
684 | 307 | mRloc16, |
685 | 307 | mLinkQualityIn, |
686 | 307 | mAverageRssi, |
687 | 307 | mLastRssi, |
688 | 307 | mAge, |
689 | 307 | mLinkFrameCounter, |
690 | 307 | mMleFrameCounter, |
691 | 307 | mIsChild ? "yes" : "no", |
692 | 307 | mRxOnWhenIdle ? "yes" : "no", |
693 | 307 | mFullFunction ? "yes" : "no", |
694 | 307 | mSecureDataRequest ? "yes" : "no", |
695 | 307 | mFullNetworkData ? "yes" : "no" |
696 | 307 | ); |
697 | 307 | break; |
698 | | |
699 | 160 | case kNeighborTableErrorRates: |
700 | 160 | snprintf(c_string, sizeof(c_string), |
701 | 160 | "%02X%02X%02X%02X%02X%02X%02X%02X, " |
702 | 160 | "RLOC16:%04x, " |
703 | 160 | "FrameErrRate:%.2lf%%, " |
704 | 160 | "MsgErrorRate:%.2lf%%, " |
705 | 160 | "AveRssi:%d, " |
706 | 160 | "LastRssi:%d, ", |
707 | 160 | mExtAddress[0], mExtAddress[1], mExtAddress[2], mExtAddress[3], |
708 | 160 | mExtAddress[4], mExtAddress[5], mExtAddress[6], mExtAddress[7], |
709 | 160 | mRloc16, |
710 | 160 | static_cast<double>(mFrameErrorRate) * 100.0 / 0xffff, |
711 | 160 | static_cast<double>(mMessageErrorRate) * 100.0 / 0xffff, |
712 | 160 | mAverageRssi, |
713 | 160 | mLastRssi |
714 | 160 | ); |
715 | 160 | break; |
716 | | |
717 | 220 | case kRouterTable: |
718 | 220 | snprintf(c_string, sizeof(c_string), |
719 | 220 | "%02X%02X%02X%02X%02X%02X%02X%02X, " |
720 | 220 | "RLOC16:%04x, " |
721 | 220 | "RouterId:%d, " |
722 | 220 | "NextHop:%d, " |
723 | 220 | "PathCost:%d, " |
724 | 220 | "LQIn:%d, " |
725 | 220 | "LQOut:%d, " |
726 | 220 | "Age:%d, " |
727 | 220 | "LinkEst:%s", |
728 | 220 | mExtAddress[0], mExtAddress[1], mExtAddress[2], mExtAddress[3], |
729 | 220 | mExtAddress[4], mExtAddress[5], mExtAddress[6], mExtAddress[7], |
730 | 220 | mRloc16, |
731 | 220 | mRouterId, |
732 | 220 | mNextHop, |
733 | 220 | mPathCost, |
734 | 220 | mLinkQualityIn, |
735 | 220 | mLinkQualityOut, |
736 | 220 | mAge, |
737 | 220 | mLinkEstablished ? "yes" : "no" |
738 | 220 | ); |
739 | 220 | break; |
740 | | |
741 | 0 | default: |
742 | 0 | c_string[0] = 0; |
743 | 0 | break; |
744 | 1.00k | } |
745 | | |
746 | 1.00k | bail: |
747 | 1.00k | return std::string(c_string); |
748 | 1.00k | } |
749 | | |
750 | | ValueMap |
751 | | SpinelNCPTaskGetNetworkTopology::TableEntry::get_as_valuemap(void) const |
752 | 0 | { |
753 | 0 | ValueMap entryMap; |
754 | 0 | uint64_t addr; |
755 | |
|
756 | 0 | if ((mType == kRouterTable) || (mType == kChildTableAddresses)) { |
757 | 0 | goto bail; |
758 | 0 | } |
759 | | |
760 | 0 | addr = (uint64_t) mExtAddress[7]; |
761 | 0 | addr |= (uint64_t) mExtAddress[6] << 8; |
762 | 0 | addr |= (uint64_t) mExtAddress[5] << 16; |
763 | 0 | addr |= (uint64_t) mExtAddress[4] << 24; |
764 | 0 | addr |= (uint64_t) mExtAddress[3] << 32; |
765 | 0 | addr |= (uint64_t) mExtAddress[2] << 40; |
766 | 0 | addr |= (uint64_t) mExtAddress[1] << 48; |
767 | 0 | addr |= (uint64_t) mExtAddress[0] << 56; |
768 | |
|
769 | 0 | #define SPINEL_TOPO_MAP_INSERT(KEY, VAL) entryMap.insert( std::pair<std::string, boost::any>( KEY, VAL ) ) |
770 | |
|
771 | 0 | if ((mType == kChildTable) || (mType == kNeighborTable) || (mType == kNeighborTableErrorRates)) { |
772 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_ExtAddress, addr ); |
773 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_RLOC16, mRloc16 ); |
774 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_AverageRssi, mAverageRssi ); |
775 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_LastRssi, mLastRssi ); |
776 | 0 | } |
777 | |
|
778 | 0 | if ((mType == kChildTable) || (mType == kNeighborTable)) { |
779 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_LinkQualityIn, mLinkQualityIn ); |
780 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_Age, mAge ); |
781 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_RxOnWhenIdle, mRxOnWhenIdle ); |
782 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_FullFunction, mFullFunction ); |
783 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_SecureDataRequest, mSecureDataRequest ); |
784 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_FullNetworkData, mFullNetworkData ); |
785 | 0 | } |
786 | |
|
787 | 0 | if (mType == kChildTable) { |
788 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_Timeout, mTimeout ); |
789 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_NetworkDataVersion, mNetworkDataVersion); |
790 | 0 | } |
791 | |
|
792 | 0 | if (mType == kNeighborTable) { |
793 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_LinkFrameCounter, mLinkFrameCounter ); |
794 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_MleFrameCounter, mMleFrameCounter ); |
795 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_IsChild, mIsChild ); |
796 | 0 | } |
797 | |
|
798 | 0 | if (mType == kNeighborTableErrorRates) { |
799 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_FrameErrorRate, mFrameErrorRate ); |
800 | 0 | SPINEL_TOPO_MAP_INSERT( kWPANTUNDValueMapKey_NetworkTopology_MessageErrorRate, mMessageErrorRate ); |
801 | 0 | } |
802 | |
|
803 | 0 | bail: |
804 | 0 | return entryMap; |
805 | 0 | } |