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