1#!/usr/bin/env python3 2# 3# Copyright (c) 2016, The OpenThread Authors. 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# 1. Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# 2. Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# 3. Neither the name of the copyright holder nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27# POSSIBILITY OF SUCH DAMAGE. 28# 29 30import io 31import logging 32import struct 33 34from binascii import hexlify 35 36import common 37 38from enum import IntEnum 39from tlvs_parsing import UnknownTlvFactory 40 41 42class CommandType(IntEnum): 43 LINK_REQUEST = 0 44 LINK_ACCEPT = 1 45 LINK_ACCEPT_AND_REQUEST = 2 46 LINK_REJECT = 3 47 ADVERTISEMENT = 4 48 UPDATE = 5 49 UPDATE_REQUEST = 6 50 DATA_REQUEST = 7 51 DATA_RESPONSE = 8 52 PARENT_REQUEST = 9 53 PARENT_RESPONSE = 10 54 CHILD_ID_REQUEST = 11 55 CHILD_ID_RESPONSE = 12 56 CHILD_UPDATE_REQUEST = 13 57 CHILD_UPDATE_RESPONSE = 14 58 ANNOUNCE = 15 59 DISCOVERY_REQUEST = 16 60 DISCOVERY_RESPONSE = 17 61 LINK_METRICS_MANAGEMENT_REQUEST = 18 62 LINK_METRICS_MANAGEMENT_RESPONSE = 19 63 LINK_PROBE = 20 64 TIME_SYNC = 99 65 66 67class TlvType(IntEnum): 68 SOURCE_ADDRESS = 0 69 MODE = 1 70 TIMEOUT = 2 71 CHALLENGE = 3 72 RESPONSE = 4 73 LINK_LAYER_FRAME_COUNTER = 5 74 MLE_FRAME_COUNTER = 8 75 ROUTE64 = 9 76 ADDRESS16 = 10 77 LEADER_DATA = 11 78 NETWORK_DATA = 12 79 TLV_REQUEST = 13 80 SCAN_MASK = 14 81 CONNECTIVITY = 15 82 LINK_MARGIN = 16 83 STATUS = 17 84 VERSION = 18 85 ADDRESS_REGISTRATION = 19 86 CHANNEL = 20 87 PANID = 21 88 ACTIVE_TIMESTAMP = 22 89 PENDING_TIMESTAMP = 23 90 ACTIVE_OPERATIONAL_DATASET = 24 91 PENDING_OPERATIONAL_DATASET = 25 92 THREAD_DISCOVERY = 26 93 SUPERVISION_INTERVAL = 27 94 CSL_CHANNEL = 80 95 CSL_SYNCHRONIZED_TIMEOUT = 85 96 CSL_CLOCK_ACCURACY = 86 97 LINK_METRICS_QUERY = 87 98 LINK_METRICS_MANAGEMENT = 88 99 LINK_METRICS_REPORT = 89 100 LINK_PROBE = 90 101 TIME_REQUEST = 252 102 TIME_PARAMETER = 253 103 104 105class LinkMetricsSubTlvType(IntEnum): 106 LINK_METRICS_REPORT = 0 107 LINK_METRICS_QUERY_ID = 1 108 LINK_METRICS_QUERY_OPTIONS = 2 109 FORWARD_PROBING_REGISTRATION = 3 110 LINK_METRICS_STATUS = 5 111 ENHANCED_ACK_LINK_METRICS_CONFIGURATION = 7 112 113 114class SourceAddress(object): 115 116 def __init__(self, address): 117 self._address = address 118 119 @property 120 def address(self): 121 return self._address 122 123 def __eq__(self, other): 124 common.expect_the_same_class(self, other) 125 126 return self.address == other.address 127 128 def __repr__(self): 129 return "SourceAddress(address={})".format(hex(self._address)) 130 131 132class SourceAddressFactory: 133 134 def parse(self, data, message_info): 135 address = struct.unpack(">H", data.read(2))[0] 136 return SourceAddress(address) 137 138 139class Mode(object): 140 141 def __init__(self, receiver, secure, device_type, network_data): 142 self._receiver = receiver 143 self._secure = secure 144 self._device_type = device_type 145 self._network_data = network_data 146 147 @property 148 def receiver(self): 149 return self._receiver 150 151 @property 152 def secure(self): 153 return self._secure 154 155 @property 156 def device_type(self): 157 return self._device_type 158 159 @property 160 def network_data(self): 161 return self._network_data 162 163 def __eq__(self, other): 164 common.expect_the_same_class(self, other) 165 166 return (self.receiver == other.receiver and self.secure == other.secure and 167 self.device_type == other.device_type and self.network_data == other.network_data) 168 169 def __repr__(self): 170 return "Mode(receiver={}, secure={}, device_type={}, network_data={})".format( 171 self.receiver, self.secure, self.device_type, self.network_data) 172 173 174class ModeFactory: 175 176 def parse(self, data, message_info): 177 mode = ord(data.read(1)) 178 receiver = (mode >> 3) & 0x01 179 secure = (mode >> 2) & 0x01 180 device_type = (mode >> 1) & 0x01 181 network_data = (mode >> 0) & 0x01 182 return Mode(receiver, secure, device_type, network_data) 183 184 185class Timeout(object): 186 187 def __init__(self, timeout): 188 self._timeout = timeout 189 190 @property 191 def timeout(self): 192 return self._timeout 193 194 def __eq__(self, other): 195 common.expect_the_same_class(self, other) 196 197 return self.timeout == other.timeout 198 199 def __repr__(self): 200 return "Timeout(timeout={})".format(self.timeout) 201 202 203class TimeoutFactory: 204 205 def parse(self, data, message_info): 206 timeout = struct.unpack(">I", data.read(4))[0] 207 return Timeout(timeout) 208 209 210class Challenge(object): 211 212 def __init__(self, challenge): 213 self._challenge = challenge 214 215 @property 216 def challenge(self): 217 return self._challenge 218 219 def __eq__(self, other): 220 common.expect_the_same_class(self, other) 221 222 return self.challenge == other.challenge 223 224 def __repr__(self): 225 return "Challenge(challenge={})".format(hexlify(self.challenge)) 226 227 228class ChallengeFactory: 229 230 def parse(self, data, message_info): 231 challenge = data.read() 232 return Challenge(challenge) 233 234 235class Response(object): 236 237 def __init__(self, response): 238 self._response = response 239 240 @property 241 def response(self): 242 return self._response 243 244 def __eq__(self, other): 245 common.expect_the_same_class(self, other) 246 247 return self.response == other.response 248 249 def __repr__(self): 250 return "Response(response={})".format(hexlify(self.response)) 251 252 253class ResponseFactory: 254 255 def parse(self, data, message_info): 256 response = data.read() 257 return Response(response) 258 259 260class LinkLayerFrameCounter(object): 261 262 def __init__(self, frame_counter): 263 self._frame_counter = frame_counter 264 265 @property 266 def frame_counter(self): 267 return self._frame_counter 268 269 def __eq__(self, other): 270 common.expect_the_same_class(self, other) 271 272 return self.frame_counter == other.frame_counter 273 274 def __repr__(self): 275 return "LinkLayerFrameCounter(frame_counter={})".format(self.frame_counter) 276 277 278class LinkLayerFrameCounterFactory: 279 280 def parse(self, data, message_info): 281 frame_counter = struct.unpack(">I", data.read(4))[0] 282 return LinkLayerFrameCounter(frame_counter) 283 284 285class MleFrameCounter(object): 286 287 def __init__(self, frame_counter): 288 self._frame_counter = frame_counter 289 290 @property 291 def frame_counter(self): 292 return self._frame_counter 293 294 def __eq__(self, other): 295 common.expect_the_same_class(self, other) 296 297 return self.frame_counter == other.frame_counter 298 299 def __repr__(self): 300 return "MleFrameCounter(frame_counter={})".format(self.frame_counter) 301 302 303class MleFrameCounterFactory: 304 305 def parse(self, data, message_info): 306 frame_counter = struct.unpack(">I", data.read(4))[0] 307 return MleFrameCounter(frame_counter) 308 309 310class LinkQualityAndRouteData(object): 311 312 def __init__(self, output, _input, route): 313 self._output = output 314 self._input = _input 315 self._route = route 316 317 @property 318 def output(self): 319 return self._output 320 321 @property 322 def input(self): 323 return self._input 324 325 @property 326 def route(self): 327 return self._route 328 329 def __eq__(self, other): 330 common.expect_the_same_class(self, other) 331 332 return (self.output == other.output and self.input == other.input and self.route == other.route) 333 334 def __repr__(self): 335 return "LinkQualityAndRouteData(ouput={}, input={}, route={})".format(self.output, self.input, self.route) 336 337 338class LinkQualityAndRouteDataFactory: 339 340 def parse(self, data, message_info): 341 lqrd = ord(data.read(1)) 342 output = (lqrd >> 6) & 0x3 343 _input = (lqrd >> 4) & 0x3 344 route = lqrd & 0x0F 345 return LinkQualityAndRouteData(output, _input, route) 346 347 348class Route64(object): 349 350 def __init__(self, id_sequence, router_id_mask, link_quality_and_route_data): 351 self._id_sequence = id_sequence 352 self._router_id_mask = router_id_mask 353 self._link_quality_and_route_data = link_quality_and_route_data 354 355 @property 356 def id_sequence(self): 357 return self._id_sequence 358 359 @property 360 def router_id_mask(self): 361 return self._router_id_mask 362 363 @property 364 def link_quality_and_route_data(self): 365 return self._link_quality_and_route_data 366 367 def __eq__(self, other): 368 common.expect_the_same_class(self, other) 369 370 return (self.id_sequence == other.id_sequence and self.router_id_mask == other.router_id_mask and 371 self.link_quality_and_route_data == other.link_quality_and_route_data) 372 373 def __repr__(self): 374 lqrd_str = ", ".join(["{}".format(lqrd) for lqrd in self.link_quality_and_route_data]) 375 return "Route64(id_sequence={}, router_id_mask={}, link_quality_and_route_data=[{}])".format( 376 self.id_sequence, hex(self.router_id_mask), lqrd_str) 377 378 379class Route64Factory: 380 381 def __init__(self, link_quality_and_route_data_factory): 382 self._lqrd_factory = link_quality_and_route_data_factory 383 384 def parse(self, data, message_info): 385 id_sequence = ord(data.read(1)) 386 router_id_mask = struct.unpack(">Q", data.read(8))[0] 387 388 link_quality_and_route_data = [] 389 390 while data.tell() < len(data.getvalue()): 391 link_quality_and_route_data.append(self._lqrd_factory.parse(data, message_info)) 392 393 return Route64(id_sequence, router_id_mask, link_quality_and_route_data) 394 395 396class Address16(object): 397 398 def __init__(self, address): 399 self._address = address 400 401 @property 402 def address(self): 403 return self._address 404 405 def __eq__(self, other): 406 common.expect_the_same_class(self, other) 407 408 return self.address == other.address 409 410 def __repr__(self): 411 return "Address16(address={})".format(hex(self.address)) 412 413 414class Address16Factory: 415 416 def parse(self, data, message_info): 417 address = struct.unpack(">H", data.read(2))[0] 418 return Address16(address) 419 420 421class LeaderData(object): 422 423 def __init__( 424 self, 425 partition_id, 426 weighting, 427 data_version, 428 stable_data_version, 429 leader_router_id, 430 ): 431 self._partition_id = partition_id 432 self._weighting = weighting 433 self._data_version = data_version 434 self._stable_data_version = stable_data_version 435 self._leader_router_id = leader_router_id 436 437 @property 438 def partition_id(self): 439 return self._partition_id 440 441 @property 442 def weighting(self): 443 return self._weighting 444 445 @property 446 def data_version(self): 447 return self._data_version 448 449 @property 450 def stable_data_version(self): 451 return self._stable_data_version 452 453 @property 454 def leader_router_id(self): 455 return self._leader_router_id 456 457 def __eq__(self, other): 458 common.expect_the_same_class(self, other) 459 460 return (self.partition_id == other.partition_id and self.weighting == other.weighting and 461 self.data_version == other.data_version and self.stable_data_version == other.stable_data_version and 462 self.leader_router_id == other.leader_router_id) 463 464 def __repr__(self): 465 return 'LeaderData(partition_id={}, weighting={}, data_version={}, stable_data_version={},leader_router_id={}'.format( 466 self.partition_id, 467 self.weighting, 468 self.data_version, 469 self.stable_data_version, 470 self.leader_router_id, 471 ) 472 473 474class LeaderDataFactory: 475 476 def parse(self, data, message_info): 477 partition_id = struct.unpack(">I", data.read(4))[0] 478 weighting = ord(data.read(1)) 479 data_version = ord(data.read(1)) 480 stable_data_version = ord(data.read(1)) 481 leader_router_id = ord(data.read(1)) 482 return LeaderData( 483 partition_id, 484 weighting, 485 data_version, 486 stable_data_version, 487 leader_router_id, 488 ) 489 490 491class NetworkData(object): 492 493 def __init__(self, tlvs): 494 self._tlvs = tlvs 495 496 @property 497 def tlvs(self): 498 return self._tlvs 499 500 def __eq__(self, other): 501 common.expect_the_same_class(self, other) 502 503 return self.tlvs == other.tlvs 504 505 def __repr__(self): 506 tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.tlvs]) 507 return "NetworkData(tlvs=[{}])".format(tlvs_str) 508 509 510class NetworkDataFactory: 511 512 def __init__(self, network_data_tlvs_factory): 513 self._tlvs_factory = network_data_tlvs_factory 514 515 def parse(self, data, message_info): 516 tlvs = self._tlvs_factory.parse(data, message_info) 517 return NetworkData(tlvs) 518 519 520class TlvRequest(object): 521 522 def __init__(self, tlvs): 523 self._tlvs = tlvs 524 525 @property 526 def tlvs(self): 527 return self._tlvs 528 529 def __eq__(self, other): 530 common.expect_the_same_class(self, other) 531 532 return self.tlvs == other.tlvs 533 534 def __repr__(self): 535 tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.tlvs]) 536 return "TlvRequest(tlvs=[{}])".format(tlvs_str) 537 538 539class TlvRequestFactory: 540 541 def parse(self, data, message_info): 542 tlvs = [b for b in bytearray(data.read())] 543 return TlvRequest(tlvs) 544 545 546class ScanMask(object): 547 548 def __init__(self, router, end_device): 549 self._router = router 550 self._end_device = end_device 551 552 @property 553 def router(self): 554 return self._router 555 556 @property 557 def end_device(self): 558 return self._end_device 559 560 def __eq__(self, other): 561 common.expect_the_same_class(self, other) 562 563 return (self.router == other.router and self.end_device == other.end_device) 564 565 def __repr__(self): 566 return "ScanMask(router={}, end_device={})".format(self.router, self.end_device) 567 568 569class ScanMaskFactory: 570 571 def parse(self, data, message_info): 572 scan_mask = ord(data.read(1)) 573 router = (scan_mask >> 7) & 0x01 574 end_device = (scan_mask >> 6) & 0x01 575 return ScanMask(router, end_device) 576 577 578class Connectivity(object): 579 580 def __init__( 581 self, 582 pp_byte, 583 link_quality_3, 584 link_quality_2, 585 link_quality_1, 586 leader_cost, 587 id_sequence, 588 active_routers, 589 sed_buffer_size=None, 590 sed_datagram_count=None, 591 ): 592 self._pp_byte = pp_byte 593 self._link_quality_3 = link_quality_3 594 self._link_quality_2 = link_quality_2 595 self._link_quality_1 = link_quality_1 596 self._leader_cost = leader_cost 597 self._id_sequence = id_sequence 598 self._active_routers = active_routers 599 self._sed_buffer_size = sed_buffer_size 600 self._sed_datagram_count = sed_datagram_count 601 602 @property 603 def pp_byte(self): 604 return self._pp_byte 605 606 @property 607 def pp(self): 608 return common.map_pp(self._pp_byte) 609 610 @property 611 def link_quality_3(self): 612 return self._link_quality_3 613 614 @property 615 def link_quality_2(self): 616 return self._link_quality_2 617 618 @property 619 def link_quality_1(self): 620 return self._link_quality_1 621 622 @property 623 def leader_cost(self): 624 return self._leader_cost 625 626 @property 627 def id_sequence(self): 628 return self._id_sequence 629 630 @property 631 def active_routers(self): 632 return self._active_routers 633 634 @property 635 def sed_buffer_size(self): 636 return self._sed_buffer_size 637 638 @property 639 def sed_datagram_count(self): 640 return self._sed_datagram_count 641 642 def __eq__(self, other): 643 common.expect_the_same_class(self, other) 644 645 return (self.pp == other.pp and self.link_quality_3 == other.link_quality_3 and 646 self.link_quality_2 == other.link_quality_2 and self.link_quality_1 == other.link_quality_1 and 647 self.leader_cost == other.leader_cost and self.id_sequence == other.id_sequence and 648 self.active_routers == other.active_routers and self.sed_buffer_size == other.sed_buffer_size and 649 self.sed_datagram_count == other.sed_datagram_count) 650 651 def __repr__(self): 652 return r"Connectivity(pp={}, \ 653 link_quality_3={}, \ 654 link_quality_2={}, \ 655 link_quality_1={}, \ 656 leader_cost={}, \ 657 id_sequence={}, \ 658 active_routers={}, \ 659 sed_buffer_size={}, \ 660 sed_datagram_count={})".format( 661 self.pp, 662 self.link_quality_3, 663 self.link_quality_2, 664 self.link_quality_1, 665 self.leader_cost, 666 self.id_sequence, 667 self.active_routers, 668 self.sed_buffer_size, 669 self.sed_datagram_count, 670 ) 671 672 673class ConnectivityFactory: 674 675 def parse(self, data, message_info): 676 pp_byte = ord(data.read(1)) 677 link_quality_3 = ord(data.read(1)) 678 link_quality_2 = ord(data.read(1)) 679 link_quality_1 = ord(data.read(1)) 680 leader_cost = ord(data.read(1)) 681 id_sequence = ord(data.read(1)) 682 active_routers = ord(data.read(1)) 683 684 sed_data = io.BytesIO(data.read(3)) 685 686 if len(sed_data.getvalue()) > 0: 687 sed_buffer_size = struct.unpack(">H", sed_data.read(2))[0] 688 sed_datagram_count = ord(sed_data.read(1)) 689 else: 690 sed_buffer_size = None 691 sed_datagram_count = None 692 693 return Connectivity( 694 pp_byte, 695 link_quality_3, 696 link_quality_2, 697 link_quality_1, 698 leader_cost, 699 id_sequence, 700 active_routers, 701 sed_buffer_size, 702 sed_datagram_count, 703 ) 704 705 706class LinkMargin(object): 707 708 def __init__(self, link_margin): 709 self._link_margin = link_margin 710 711 @property 712 def link_margin(self): 713 return self._link_margin 714 715 def __eq__(self, other): 716 common.expect_the_same_class(self, other) 717 718 return self.link_margin == other.link_margin 719 720 def __repr__(self): 721 return "LinkMargin(link_margin={})".format(self.link_margin) 722 723 724class LinkMarginFactory: 725 726 def parse(self, data, message_info): 727 link_margin = ord(data.read(1)) 728 return LinkMargin(link_margin) 729 730 731class Status(object): 732 733 def __init__(self, status): 734 self._status = status 735 736 @property 737 def status(self): 738 return self._status 739 740 def __eq__(self, other): 741 common.expect_the_same_class(self, other) 742 743 return self.status == other.status 744 745 def __repr__(self): 746 return "Status(status={})".format(self.status) 747 748 749class StatusFactory: 750 751 def parse(self, data, message_info): 752 status = ord(data.read(1)) 753 return Status(status) 754 755 756class Version(object): 757 758 def __init__(self, version): 759 self._version = version 760 761 @property 762 def version(self): 763 return self._version 764 765 def __eq__(self, other): 766 common.expect_the_same_class(self, other) 767 768 return self.version == other.version 769 770 def __repr__(self): 771 return "Version(version={})".format(self.version) 772 773 774class VersionFactory: 775 776 def parse(self, data, message_info): 777 version = struct.unpack(">H", data.read(2))[0] 778 return Version(version) 779 780 781class AddressFull(object): 782 783 def __init__(self, ipv6_address): 784 self._ipv6_address = ipv6_address 785 786 @property 787 def ipv6_address(self): 788 return self._ipv6_address 789 790 def __eq__(self, other): 791 common.expect_the_same_class(self, other) 792 793 return self.ipv6_address == other.ipv6_address 794 795 def __repr__(self): 796 return "AddressFull(ipv6_address={}')".format(hexlify(self.ipv6_address)) 797 798 799class AddressFullFactory: 800 801 def parse(self, data, message_info): 802 data.read(1) # first byte is ignored 803 ipv6_address = data.read(16) 804 return AddressFull(ipv6_address) 805 806 807class AddressCompressed(object): 808 809 def __init__(self, cid, iid): 810 self._cid = cid 811 self._iid = iid 812 813 @property 814 def cid(self): 815 return self._cid 816 817 @property 818 def iid(self): 819 return self._iid 820 821 def __eq__(self, other): 822 common.expect_the_same_class(self, other) 823 824 return self.cid == other.cid and self.iid == other.iid 825 826 def __repr__(self): 827 return "AddressCompressed(cid={}, iid={}')".format(self.cid, hexlify(self.iid)) 828 829 830class AddressCompressedFactory: 831 832 def parse(self, data, message_info): 833 cid = ord(data.read(1)) & 0x0F 834 iid = bytearray(data.read(8)) 835 return AddressCompressed(cid, iid) 836 837 838class AddressRegistration(object): 839 840 def __init__(self, addresses): 841 self._addresses = addresses 842 843 @property 844 def addresses(self): 845 return self._addresses 846 847 def __eq__(self, other): 848 common.expect_the_same_class(self, other) 849 850 return self.addresses == other.addresses 851 852 def __repr__(self): 853 addresses_str = ", ".join(["{}".format(address) for address in self.addresses]) 854 return "AddressRegistration(addresses=[{}])".format(addresses_str) 855 856 857class AddressRegistrationFactory: 858 859 def __init__(self, addr_compressed_factory, addr_full_factory): 860 self._addr_compressed_factory = addr_compressed_factory 861 self._addr_full_factory = addr_full_factory 862 863 def parse(self, data, message_info): 864 addresses = [] 865 866 while data.tell() < len(data.getvalue()): 867 compressed = (ord(data.read(1)) >> 7) & 0x01 868 data.seek(-1, io.SEEK_CUR) 869 870 if compressed: 871 addresses.append(self._addr_compressed_factory.parse(data, message_info)) 872 else: 873 addresses.append(self._addr_full_factory.parse(data, message_info)) 874 875 return AddressRegistration(addresses) 876 877 878class Channel(object): 879 880 def __init__(self, channel_page, channel): 881 self._channel_page = channel_page 882 self._channel = channel 883 884 @property 885 def channel_page(self): 886 return self._channel_page 887 888 @property 889 def channel(self): 890 return self._channel 891 892 def __eq__(self, other): 893 common.expect_the_same_class(self, other) 894 895 return (self.channel_page == other.channel_page and self.channel == other.channel) 896 897 def __repr__(self): 898 return "Channel(channel_page={}, channel={})".format(self.channel_page, self.channel) 899 900 901class ChannelFactory: 902 903 def parse(self, data, message_info): 904 channel_page = ord(data.read(1)) 905 channel = struct.unpack(">H", data.read(2))[0] 906 return Channel(channel_page, channel) 907 908 909class PanId: 910 911 def __init__(self, pan_id): 912 self._pan_id = pan_id 913 914 @property 915 def pan_id(self): 916 return self._pan_id 917 918 def __eq__(self, other): 919 common.expect_the_same_class(self, other) 920 921 return self.pan_id == other.pan_id 922 923 def __repr__(self): 924 return "PanId(pan_id={})".format(self.pan_id) 925 926 927class PanIdFactory: 928 929 def parse(self, data, message_info): 930 pan_id = struct.unpack(">H", data.read(2))[0] 931 return PanId(pan_id) 932 933 934class ActiveTimestamp(object): 935 936 def __init__(self, timestamp_seconds, timestamp_ticks, u): 937 self._timestamp_seconds = timestamp_seconds 938 self._timestamp_ticks = timestamp_ticks 939 self._u = u 940 941 @property 942 def timestamp_seconds(self): 943 return self._timestamp_seconds 944 945 @property 946 def timestamp_ticks(self): 947 return self._timestamp_ticks 948 949 @property 950 def u(self): 951 return self._u 952 953 def __eq__(self, other): 954 common.expect_the_same_class(self, other) 955 956 return (self.timestamp_seconds == other.timestamp_seconds and self.timestamp_ticks == other.timestamp_ticks and 957 self.u == other.u) 958 959 def __repr__(self): 960 return "ActiveTimestamp(timestamp_seconds={}, timestamp_ticks={}, u={})".format( 961 self.timestamp_seconds, self.timestamp_ticks, self.u) 962 963 964class ActiveTimestampFactory: 965 966 def parse(self, data, message_info): 967 seconds = bytearray([0x00, 0x00]) + bytearray(data.read(6)) 968 ticks = struct.unpack(">H", data.read(2))[0] 969 970 timestamp_seconds = struct.unpack(">Q", bytes(seconds))[0] 971 timestamp_ticks = ticks >> 1 972 u = ticks & 0x01 973 return ActiveTimestamp(timestamp_seconds, timestamp_ticks, u) 974 975 976class PendingTimestamp(object): 977 978 def __init__(self, timestamp_seconds, timestamp_ticks, u): 979 self._timestamp_seconds = timestamp_seconds 980 self._timestamp_ticks = timestamp_ticks 981 self._u = u 982 983 @property 984 def timestamp_seconds(self): 985 return self._timestamp_seconds 986 987 @property 988 def timestamp_ticks(self): 989 return self._timestamp_ticks 990 991 @property 992 def u(self): 993 return self._u 994 995 def __eq__(self, other): 996 common.expect_the_same_class(self, other) 997 998 return (self.timestamp_seconds == other.timestamp_seconds and self.timestamp_ticks == other.timestamp_ticks and 999 self.u == other.u) 1000 1001 def __repr__(self): 1002 return "PendingTimestamp(timestamp_seconds={}, timestamp_ticks={}, u={})".format( 1003 self.timestamp_seconds, self.timestamp_ticks, self.u) 1004 1005 1006class PendingTimestampFactory: 1007 1008 def parse(self, data, message_info): 1009 seconds = bytearray([0x00, 0x00]) + bytearray(data.read(6)) 1010 ticks = struct.unpack(">H", data.read(2))[0] 1011 1012 timestamp_seconds = struct.unpack(">Q", bytes(seconds))[0] 1013 timestamp_ticks = ticks >> 1 1014 u = ticks & 0x01 1015 return PendingTimestamp(timestamp_seconds, timestamp_ticks, u) 1016 1017 1018class ActiveOperationalDataset: 1019 # TODO: Not implemented yet 1020 1021 def __init__(self): 1022 print("ActiveOperationalDataset is not implemented yet.") 1023 1024 1025class ActiveOperationalDatasetFactory: 1026 1027 def parse(self, data, message_info): 1028 return ActiveOperationalDataset() 1029 1030 1031class PendingOperationalDataset: 1032 # TODO: Not implemented yet 1033 1034 def __init__(self): 1035 print("PendingOperationalDataset is not implemented yet.") 1036 1037 1038class PendingOperationalDatasetFactory: 1039 1040 def parse(self, data, message_info): 1041 return PendingOperationalDataset() 1042 1043 1044class ThreadDiscovery(object): 1045 1046 def __init__(self, tlvs): 1047 self._tlvs = tlvs 1048 1049 @property 1050 def tlvs(self): 1051 return self._tlvs 1052 1053 def __eq__(self, other): 1054 return self.tlvs == other.tlvs 1055 1056 def __repr__(self): 1057 return "ThreadDiscovery(tlvs={})".format(self.tlvs) 1058 1059 1060class ThreadDiscoveryFactory: 1061 1062 def __init__(self, thread_discovery_tlvs_factory): 1063 self._tlvs_factory = thread_discovery_tlvs_factory 1064 1065 def parse(self, data, message_info): 1066 tlvs = self._tlvs_factory.parse(data, message_info) 1067 return ThreadDiscovery(tlvs) 1068 1069 1070class CslChannel: 1071 # TODO: Not implemented yet 1072 1073 def __init__(self): 1074 print("CslChannel is not implemented yet.") 1075 1076 1077class CslChannelFactory: 1078 # TODO: Not implemented yet 1079 1080 def parse(self, data, message_info): 1081 return CslChannel() 1082 1083 1084class CslSynchronizedTimeout: 1085 # TODO: Not implemented yet 1086 1087 def __init__(self): 1088 print("CslSynchronizedTimeout is not implemented yet.") 1089 1090 1091class CslSynchronizedTimeoutFactory: 1092 1093 def parse(self, data, message_info): 1094 return CslSynchronizedTimeout() 1095 1096 1097class CslClockAccuracy: 1098 # TODO: Not implemented yet 1099 1100 def __init__(self): 1101 print("CslClockAccuracy is not implemented yet.") 1102 1103 1104class CslClockAccuracyFactory: 1105 1106 def parse(self, data, message_info): 1107 return CslClockAccuracy() 1108 1109 1110class TimeRequest: 1111 # TODO: Not implemented yet 1112 1113 def __init__(self): 1114 print("TimeRequest is not implemented yet.") 1115 1116 1117class TimeRequestFactory: 1118 1119 def parse(self, data, message_info): 1120 return TimeRequest() 1121 1122 1123class TimeParameter: 1124 # TODO: Not implemented yet 1125 1126 def __init__(self): 1127 print("TimeParameter is not implemented yet.") 1128 1129 1130class TimeParameterFactory: 1131 1132 def parse(self, data, message_info): 1133 return TimeParameter() 1134 1135 1136class LinkMetricsQuery: 1137 # TODO: Not implemented yet 1138 1139 def __init__(self): 1140 print("LinkMetricsQuery is not implemented yet.") 1141 1142 1143class LinkMetricsQueryFactory: 1144 1145 def parse(self, data, message_info): 1146 return LinkMetricsQuery() 1147 1148 1149class LinkMetricsManagement: 1150 # TODO: Not implemented yet 1151 1152 def __init__(self): 1153 print("LinkMetricsManagement is not implemented yet.") 1154 1155 1156class LinkMetricsManagementFactory: 1157 1158 def parse(self, data, message_info): 1159 return LinkMetricsManagement() 1160 1161 1162class LinkMetricsReport: 1163 # TODO: Not implemented yet 1164 1165 def __init__(self): 1166 print("LinkMetricsReport is not implemented yet.") 1167 1168 1169class LinkMetricsReportFactory: 1170 1171 def parse(self, data, message_info): 1172 return LinkMetricsReport() 1173 1174 1175class LinkProbe: 1176 # TODO: Not implemented yet 1177 1178 def __init__(self): 1179 print("LinkProbe is not implemented yet.") 1180 1181 1182class LinkProbeFactory: 1183 1184 def parse(self, data, message_info): 1185 return LinkProbe() 1186 1187 1188class MleCommand(object): 1189 1190 def __init__(self, _type, tlvs): 1191 self._type = _type 1192 self._tlvs = tlvs 1193 1194 @property 1195 def type(self): 1196 return self._type 1197 1198 @property 1199 def tlvs(self): 1200 return self._tlvs 1201 1202 def __repr__(self): 1203 tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.tlvs]) 1204 return "MleCommand(type={}, tlvs=[{}])".format(self.type.name, tlvs_str) 1205 1206 1207class MleCommandFactory: 1208 1209 _MARKER_EXTENDED_LENGTH = 0xff 1210 1211 def __init__(self, tlvs_factories): 1212 self._tlvs_factories = tlvs_factories 1213 1214 def _get_length(self, data): 1215 length = ord(data.read(1)) 1216 1217 if length == self._MARKER_EXTENDED_LENGTH: 1218 length = struct.unpack(">H", data.read(2))[0] 1219 1220 return length 1221 1222 def _get_tlv_factory(self, _type): 1223 try: 1224 return self._tlvs_factories[_type] 1225 except KeyError: 1226 logging.error('Could not find TLV factory. Unsupported TLV type: {}'.format(_type)) 1227 return UnknownTlvFactory(_type) 1228 1229 def _parse_tlv(self, data, message_info): 1230 _type = TlvType(ord(data.read(1))) 1231 length = self._get_length(data) 1232 value = data.read(length) 1233 1234 factory = self._get_tlv_factory(_type) 1235 1236 return factory.parse(io.BytesIO(value), message_info) 1237 1238 def parse(self, data, message_info): 1239 cmd_type = CommandType(ord(data.read(1))) 1240 tlvs = [] 1241 1242 while data.tell() < len(data.getvalue()): 1243 tlv = self._parse_tlv(data, message_info) 1244 tlvs.append(tlv) 1245 1246 return MleCommand(cmd_type, tlvs) 1247 1248 1249class MleMessage(object): 1250 1251 def __init__(self, command): 1252 self._command = command 1253 1254 @property 1255 def command(self): 1256 return self._command 1257 1258 def __repr__(self): 1259 return "MleMessage(command={})".format(self.command) 1260 1261 1262class MleMessageSecured(MleMessage): 1263 1264 def __init__(self, aux_sec_hdr, command, mic): 1265 super(MleMessageSecured, self).__init__(command) 1266 self._aux_sec_hdr = aux_sec_hdr 1267 self._mic = mic 1268 1269 @property 1270 def aux_sec_hdr(self): 1271 return self._aux_sec_hdr 1272 1273 @property 1274 def mic(self): 1275 return self._mic 1276 1277 def __repr__(self): 1278 return "MleMessageSecured(aux_sec_hdr={}, command={}, mic=\"{}\")".format(self.aux_sec_hdr, self.command, 1279 hexlify(self.mic)) 1280 1281 1282class MleMessageFactory: 1283 1284 def __init__(self, aux_sec_hdr_factory, mle_command_factory, crypto_engine): 1285 self._aux_sec_hdr_factory = aux_sec_hdr_factory 1286 self._mle_command_factory = mle_command_factory 1287 self._crypto_engine = crypto_engine 1288 1289 def _create_mle_secured_message(self, data, message_info): 1290 aux_sec_hdr = self._aux_sec_hdr_factory.parse(data, message_info) 1291 1292 enc_data_length = len(data.getvalue()) 1293 1294 enc_data = bytearray(data.read(enc_data_length - data.tell() - self._crypto_engine.mic_length)) 1295 mic = bytearray(data.read()) 1296 1297 dec_data = self._crypto_engine.decrypt(enc_data, mic, message_info) 1298 1299 command = self._mle_command_factory.parse(io.BytesIO(dec_data), message_info) 1300 1301 return MleMessageSecured(aux_sec_hdr, command, mic) 1302 1303 def _create_mle_message(self, data, message_info): 1304 command = self._mle_command_factory.parse(data, message_info) 1305 1306 return MleMessage(command) 1307 1308 def parse(self, data, message_info): 1309 security_indicator = ord(data.read(1)) 1310 1311 if security_indicator == 0: 1312 return self._create_mle_secured_message(data, message_info) 1313 1314 elif security_indicator == 255: 1315 return self._create_mle_message(data, message_info) 1316 1317 else: 1318 raise RuntimeError( 1319 "Could not create MLE message. Unknown security indicator value: {}".format(security_indicator)) 1320