1#!/usr/bin/env python3 2# 3# Copyright (c) 2019, 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 30from binascii import hexlify 31from enum import IntEnum 32import io 33import logging 34import struct 35 36from network_data import SubTlvsFactory 37from tlvs_parsing import UnknownTlvFactory 38import common 39 40 41class TlvType(IntEnum): 42 CHANNEL = 0 43 PAN_ID = 1 44 EXTENDED_PANID = 2 45 NETWORK_NAME = 3 46 PSKC = 4 47 NETWORK_KEY = 5 48 NETWORK_KEY_SEQUENCE_COUNTER = 6 49 NETWORK_MESH_LOCAL_PREFIX = 7 50 STEERING_DATA = 8 51 BORDER_AGENT_LOCATOR = 9 52 COMMISSIONER_ID = 10 53 COMMISSIONER_SESSION_ID = 11 54 SECURITY_POLICY = 12 55 GET = 13 56 ACTIVE_TIMESTAMP = 14 57 COMMISSIONER_UDP_PORT = 15 58 STATE = 16 59 JOINER_DTLS_ENCAPSULATION = 17 60 JOINER_UDP_PORT = 18 61 JOINER_IID = 19 62 JOINER_ROUTER_LOCATOR = 20 63 JOINER_ROUTER_KEK = 21 64 PROVISIONING_URL = 32 65 VENDOR_NAME = 33 66 VENDOR_MODEL = 34 67 VENDOR_SW_VERSION = 35 68 VENDOR_DATA = 36 69 VENDOR_STACK_VERSION = 37 70 UDP_ENCAPSULATION = 48 71 IPV6_ADDRESS = 49 72 PENDING_TIMESTAMP = 51 73 DELAY_TIMER = 52 74 CHANNEL_MASK = 53 75 COUNT = 54 76 PERIOD = 55 77 SCAN_DURATION = 56 78 ENERGY_LIST = 57 79 CSL_SYNCHRONIZED_TIMEOUT = 85 80 CSL_CLOCK_ACCURACY = 86 81 DISCOVERY_REQUEST = 128 82 DISCOVERY_RESPONSE = 129 83 84 85class MeshCopState(IntEnum): 86 ACCEPT = 0x1 87 REJECT = 0xff 88 89 90class MeshCopMessageType(IntEnum): 91 JOIN_FIN_REQ = (1,) 92 JOIN_FIN_RSP = (2,) 93 JOIN_ENT_NTF = (3,) 94 JOIN_ENT_RSP = 4 95 96 97def create_mesh_cop_message_type_set(): 98 return [ 99 MeshCopMessageType.JOIN_FIN_REQ, 100 MeshCopMessageType.JOIN_FIN_RSP, 101 MeshCopMessageType.JOIN_ENT_NTF, 102 MeshCopMessageType.JOIN_ENT_RSP, 103 ] 104 105 106# Channel TLV (0) 107class Channel(object): 108 109 def __init__(self, channel_page, channel): 110 self._channel_page = channel_page 111 self._channel = channel 112 113 @property 114 def channel_page(self): 115 return self._channel_page 116 117 @property 118 def channel(self): 119 return self._channel 120 121 def __eq__(self, other): 122 common.expect_the_same_class(self, other) 123 124 return (self._channel_page == other._channel_page and self._channel == other.__channel) 125 126 def __repr__(self): 127 return 'Channel(channel_page={},channel={})'.format(self._channel_page, self._channel) 128 129 def to_hex(self): 130 return struct.pack('>BBBH', TlvType.CHANNEL, 3, self.channel_page, self.channel) 131 132 133class ChannelFactory(object): 134 135 def parse(self, data, message_info): 136 data_tp = struct.unpack('>BH', data.read(3)) 137 channel_page = data_tp[0] 138 channel = data_tp[1] 139 return Channel(channel_page, channel) 140 141 142# PanId TLV (1) 143class Panid(object): 144 # TODO: Not implemented yet 145 pass 146 147 148class PanidFactory(object): 149 # TODO: Not implemented yet 150 151 def parse(self, data, message_info): 152 raise NotImplementedError("TODO: Not implemented yet") 153 154 155# ExtendedPanid TLV (2) 156class ExtendedPanid(object): 157 158 def __init__(self, extended_panid): 159 self._extended_panid = extended_panid 160 161 @property 162 def extended_panid(self): 163 return self._extended_panid 164 165 def __eq__(self, other): 166 return (isinstance(self, type(other)) and self.extended_panid == other.extended_panid) 167 168 def __repr__(self): 169 return "ExtendedPanid(extended_panid={})".format(self.extended_panid) 170 171 172class ExtendedPanidFactory(object): 173 174 def parse(self, data, message_info): 175 extended_panid = struct.unpack(">Q", data.read(8))[0] 176 return ExtendedPanid(extended_panid) 177 178 179# NetworkName TLV (3) 180class NetworkName(object): 181 182 def __init__(self, network_name): 183 self._network_name = network_name 184 185 @property 186 def network_name(self): 187 return self._network_name 188 189 def __eq__(self, other): 190 return (isinstance(self, type(other)) and self.network_name == other.network_name) 191 192 def __repr__(self): 193 return "NetworkName(network_name={})".format(self.network_name) 194 195 196class NetworkNameFactory(object): 197 198 def parse(self, data, message_info): 199 len = message_info.length 200 network_name = struct.unpack("{}s".format(10), data.read(len))[0] 201 return NetworkName(network_name) 202 203 204# PSKc TLV (4) 205class PSKc(object): 206 # TODO: Not implemented yet 207 pass 208 209 210class PSKcFactory(object): 211 # TODO: Not implemented yet 212 213 def parse(self, data, message_info): 214 raise NotImplementedError("TODO: Not implemented yet") 215 216 217# NetworkKey TLV (5) 218class NetworkKey(object): 219 # TODO: Not implemented yet 220 pass 221 222 223class NetworkKeyFactory(object): 224 # TODO: Not implemented yet 225 226 def parse(self, data, message_info): 227 raise NotImplementedError("TODO: Not implemented yet") 228 229 230# NetworkKeySequenceCounter TLV (6) 231class NetworkKeySequenceCounter(object): 232 # TODO: Not implemented yet 233 pass 234 235 236class NetworkKeySequenceCounterFactory(object): 237 # TODO: Not implemented yet 238 239 def parse(self, data, message_info): 240 raise NotImplementedError("TODO: Not implemented yet") 241 242 243# NetworkMeshLocalPrefix TLV (7) 244class NetworkMeshLocalPrefix(object): 245 # TODO: Not implemented yet 246 pass 247 248 249class NetworkMeshLocalPrefixFactory(object): 250 # TODO: Not implemented yet 251 252 def parse(self, data, message_info): 253 raise NotImplementedError("TODO: Not implemented yet") 254 255 256# Steering Data TLV (8) 257class SteeringData(object): 258 259 def __init__(self, bloom_filter): 260 self._bloom_filter = bloom_filter 261 262 @property 263 def bloom_filter(self): 264 return self._bloom_filter 265 266 def __eq__(self, other): 267 common.expect_the_same_class(self, other) 268 269 return self._bloom_filter == other._bloom_filter 270 271 def __repr__(self): 272 return "SteeringData(bloom_filter={})".format(hexlify(self._bloom_filter)) 273 274 def to_hex(self): 275 bloom_filter_len = len(self.bloom_filter) 276 return (struct.pack('>BB', TlvType.STEERING_DATA, bloom_filter_len) + self.bloom_filter) 277 278 279class SteeringDataFactory: 280 281 def parse(self, data, message_info): 282 bloom_filter = data.read(message_info.length) 283 return SteeringData(bloom_filter) 284 285 286# Border Agent Locator TLV (9) 287class BorderAgentLocator(object): 288 289 def __init__(self, address): 290 self._border_agent_locator = address 291 292 @property 293 def border_agent_locator(self): 294 return self._border_agent_locator 295 296 def __eq__(self, other): 297 common.expect_the_same_class(self, other) 298 299 return self._border_agent_locator == other._border_agent_locator 300 301 def __repr__(self): 302 return "BorderAgentLocator(rloc16={})".format(hex(self._border_agent_locator)) 303 304 def to_hex(self): 305 return struct.pack('>BBH', TlvType.BORDER_AGENT_LOCATOR, 2, self.border_agent_locator) 306 307 308class BorderAgentLocatorFactory: 309 310 def parse(self, data, message_info): 311 border_agent_locator = struct.unpack(">H", data.read(2))[0] 312 return BorderAgentLocator(border_agent_locator) 313 314 315# CommissionerId TLV (10) 316class CommissionerId(object): 317 318 def __init__(self, commissioner_id): 319 self._commissioner_id = commissioner_id 320 321 @property 322 def commissioner_id(self): 323 return self._commissioner_id 324 325 def __eq__(self, other): 326 return self.commissioner_id == other.commissioner_id 327 328 def __repr__(self): 329 return "CommissionerId(commissioner_id={})".format(self.commissioner_id) 330 331 332class CommissionerIdFactory(object): 333 334 def parse(self, data, message_info): 335 commissioner_id = data.getvalue().decode('utf-8') 336 return CommissionerId(commissioner_id) 337 338 339# Commissioner Session ID TLV (11) 340class CommissionerSessionId(object): 341 342 def __init__(self, commissioner_session_id): 343 self._commissioner_session_id = commissioner_session_id 344 345 @property 346 def commissioner_session_id(self): 347 return self._commissioner_session_id 348 349 def __eq__(self, other): 350 common.expect_the_same_class(self, other) 351 352 return self._commissioner_session_id == other._commissioner_session_id 353 354 def __repr__(self): 355 return "CommissionerSessionId(commissioner_session_id={})".format(self._commissioner_session_id) 356 357 def to_hex(self): 358 return struct.pack( 359 '>BBH', 360 TlvType.COMMISSIONER_SESSION_ID, 361 2, 362 self.commissioner_session_id, 363 ) 364 365 366class CommissionerSessionIdFactory: 367 368 def parse(self, data, message_info): 369 session_id = struct.unpack(">H", data.read(2))[0] 370 return CommissionerSessionId(session_id) 371 372 373# SecurityPolicy TLV (12) 374class SecurityPolicy(object): 375 # TODO: Not implemented yet 376 pass 377 378 379class SecurityPolicyFactory(object): 380 # TODO: Not implemented yet 381 382 def parse(self, data, message_info): 383 raise NotImplementedError("TODO: Not implemented yet") 384 385 386# Get TLV (13) 387class Get(object): 388 # TODO: Not implemented yet 389 pass 390 391 392class GetFactory(object): 393 # TODO: Not implemented yet 394 395 def parse(self, data, message_info): 396 raise NotImplementedError("TODO: Not implemented yet") 397 398 399# ActiveTimestamp TLV (14) 400class ActiveTimestamp(object): 401 # TODO: Not implemented yet 402 pass 403 404 405class ActiveTimestampFactory(object): 406 # TODO: Not implemented yet 407 408 def parse(self, data, message_info): 409 raise NotImplementedError("TODO: Not implemented yet") 410 411 412# Commissioner UDP Port TLV (15) 413class CommissionerUdpPort(object): 414 415 def __init__(self, udp_port): 416 self._udp_port = udp_port 417 418 @property 419 def udp_port(self): 420 return self._udp_port 421 422 def __eq__(self, other): 423 common.expect_the_same_class(self, other) 424 425 return self._udp_port == other._udp_port 426 427 def __repr__(self): 428 return "CommissionerUdpPort(udp_port={})".format(self._udp_port) 429 430 431class CommissionerUdpPortFactory: 432 433 def parse(self, data, message_info): 434 udp_port = struct.unpack(">H", data.read(2))[0] 435 return CommissionerUdpPort(udp_port) 436 437 438# State TLV (16) 439class State(object): 440 441 def __init__(self, state): 442 self._state = state 443 444 @property 445 def state(self): 446 return self._state 447 448 def __eq__(self, other): 449 return self.state == other.state 450 451 def __repr__(self): 452 return "State(state={})".format(self.state) 453 454 455class StateFactory: 456 457 def parse(self, data, message_info): 458 state = ord(data.read(1)) 459 return State(state) 460 461 462# JoinerDtlsEncapsulation TLV (17) 463class JoinerDtlsEncapsulation(object): 464 # TODO: Not implemented yet 465 pass 466 467 468class JoinerDtlsEncapsulationFactory(object): 469 # TODO: Not implemented yet 470 471 def parse(self, data, message_info): 472 raise NotImplementedError("TODO: Not implemented yet") 473 474 475# JoinerUdpPort TLV (18) 476class JoinerUdpPort(object): 477 478 def __init__(self, udp_port): 479 self._udp_port = udp_port 480 481 @property 482 def udp_port(self): 483 return self._udp_port 484 485 def __eq__(self, other): 486 return (isinstance(self, type(other)) and self.udp_port == other.udp_port) 487 488 def __repr__(self): 489 return "JoinerUdpPort(udp_port={})".format(self.udp_port) 490 491 492class JoinerUdpPortFactory(object): 493 494 def parse(self, data, message_info): 495 udp_port = struct.unpack(">H", data.read(2))[0] 496 return JoinerUdpPort(udp_port) 497 498 499# JoinerIID TLV (19) 500class JoinerIID(object): 501 # TODO: Not implemented yet 502 pass 503 504 505class JoinerIIDFactory(object): 506 # TODO: Not implemented yet 507 508 def parse(self, data, message_info): 509 raise NotImplementedError("TODO: Not implemented yet") 510 511 512# JoinerRouterLocator TLV (20) 513class JoinerRouterLocator(object): 514 # TODO: Not implemented yet 515 pass 516 517 518class JoinerRouterLocatorFactory(object): 519 # TODO: Not implemented yet 520 521 def parse(self, data, message_info): 522 raise NotImplementedError("TODO: Not implemented yet") 523 524 525# JoinerRouterKEK TLV (21) 526class JoinerRouterKEK(object): 527 # TODO: Not implemented yet 528 pass 529 530 531class JoinerRouterKEKFactory(object): 532 # TODO: Not implemented yet 533 534 def parse(self, data, message_info): 535 raise NotImplementedError("TODO: Not implemented yet") 536 537 538# ProvisioningURL TLV (32) 539class ProvisioningUrl(object): 540 541 def __init__(self, url): 542 self._url = url 543 544 @property 545 def url(self): 546 return self._url 547 548 def __repr__(self): 549 return "ProvisioningUrl(url={})".format(self.url) 550 551 552class ProvisioningUrlFactory: 553 554 def parse(self, data, message_info): 555 url = data.getvalue().decode('utf-8') 556 return ProvisioningUrl(url) 557 558 559# VendorName TLV (33) 560class VendorName(object): 561 562 def __init__(self, vendor_name): 563 self._vendor_name = vendor_name 564 565 @property 566 def vendor_name(self): 567 return self._vendor_name 568 569 def __eq__(self, other): 570 return self.vendor_name == other.vendor_name 571 572 def __repr__(self): 573 return "VendorName(vendor_name={})".format(self.vendor_name) 574 575 576class VendorNameFactory: 577 578 def parse(self, data, message_info): 579 vendor_name = data.getvalue().decode('utf-8') 580 return VendorName(vendor_name) 581 582 583# VendorModel TLV (34) 584class VendorModel(object): 585 586 def __init__(self, vendor_model): 587 self._vendor_model = vendor_model 588 589 @property 590 def vendor_model(self): 591 return self._vendor_model 592 593 def __eq__(self, other): 594 return self.vendor_model == other.vendor_model 595 596 def __repr__(self): 597 return "VendorModel(vendor_model={})".format(self.vendor_model) 598 599 600class VendorModelFactory: 601 602 def parse(self, data, message_info): 603 vendor_model = data.getvalue().decode('utf-8') 604 return VendorModel(vendor_model) 605 606 607# VendorSWVersion TLV (35) 608class VendorSWVersion(object): 609 610 def __init__(self, vendor_sw_version): 611 self._vendor_sw_version = vendor_sw_version 612 613 @property 614 def vendor_sw_version(self): 615 return self._vendor_sw_version 616 617 def __eq__(self, other): 618 return self.vendor_sw_version == other.vendor_sw_version 619 620 def __repr__(self): 621 return "VendorName(vendor_sw_version={})".format(self.vendor_sw_version) 622 623 624class VendorSWVersionFactory: 625 626 def parse(self, data, message_info): 627 vendor_sw_version = data.getvalue() 628 return VendorSWVersion(vendor_sw_version) 629 630 631# VendorData TLV (36) 632class VendorData(object): 633 634 def __init__(self, data): 635 self._vendor_data = data 636 637 @property 638 def vendor_data(self): 639 return self._vendor_data 640 641 def __repr__(self): 642 return "Vendor(url={})".format(self.vendor_data) 643 644 645class VendorDataFactory(object): 646 647 def parse(self, data, message_info): 648 return VendorData(data) 649 650 651# VendorStackVersion TLV (37) 652class VendorStackVersion(object): 653 654 def __init__(self, stack_vendor_oui, build, rev, minor, major): 655 self._stack_vendor_oui = stack_vendor_oui 656 self._build = build 657 self._rev = rev 658 self._minor = minor 659 self._major = major 660 return 661 662 @property 663 def stack_vendor_oui(self): 664 return self._stack_vendor_oui 665 666 @property 667 def build(self): 668 return self._build 669 670 @property 671 def rev(self): 672 return self._rev 673 674 @property 675 def minor(self): 676 return self._minor 677 678 @property 679 def major(self): 680 return self._major 681 682 def __repr__(self): 683 return "VendorStackVersion(vendor_stack_version={}, build={}, rev={}, minor={}, major={})".format( 684 self.stack_vendor_oui, self.build, self.rev, self.minor, self.major) 685 686 687class VendorStackVersionFactory: 688 689 def parse(self, data, message_info): 690 stack_vendor_oui = struct.unpack(">H", data.read(2))[0] 691 rest = struct.unpack(">BBBB", data.read(4)) 692 build = rest[1] << 4 | (0xf0 & rest[2]) 693 rev = 0xF & rest[2] 694 minor = rest[3] & 0xf0 695 major = rest[3] & 0xF 696 return VendorStackVersion(stack_vendor_oui, build, rev, minor, major) 697 698 699# UdpEncapsulation TLV (48) 700class UdpEncapsulation(object): 701 # TODO: Not implemented yet 702 pass 703 704 705class UdpEncapsulationFactory(object): 706 # TODO: Not implemented yet 707 708 def parse(self, data, message_info): 709 raise NotImplementedError("TODO: Not implemented yet") 710 711 712# Ipv6Address TLV (49) 713class Ipv6Address(object): 714 # TODO: Not implemented yet 715 pass 716 717 718class Ipv6AddressFactory(object): 719 # TODO: Not implemented yet 720 721 def parse(self, data, message_info): 722 raise NotImplementedError("TODO: Not implemented yet") 723 724 725# PendingTimestamp TLV (51) 726class PendingTimestamp(object): 727 # TODO: Not implemented yet 728 pass 729 730 731class PendingTimestampFactory(object): 732 # TODO: Not implemented yet 733 734 def parse(self, data, message_info): 735 raise NotImplementedError("TODO: Not implemented yet") 736 737 738# DelayTimer TLV (52) 739class DelayTimer(object): 740 # TODO: Not implemented yet 741 pass 742 743 744class DelayTimerFactory(object): 745 # TODO: Not implemented yet 746 747 def parse(self, data, message_info): 748 raise NotImplementedError("TODO: Not implemented yet") 749 750 751# ChannelMask TLV (53) 752class ChannelMask(object): 753 # TODO: Not implemented yet 754 pass 755 756 757class ChannelMaskFactory(object): 758 # TODO: Not implemented yet 759 760 def parse(self, data, message_info): 761 raise NotImplementedError("TODO: Not implemented yet") 762 763 764# Count TLV (54) 765class Count(object): 766 # TODO: Not implemented yet 767 pass 768 769 770class CountFactory(object): 771 # TODO: Not implemented yet 772 773 def parse(self, data, message_info): 774 raise NotImplementedError("TODO: Not implemented yet") 775 776 777# Period TLV (55) 778class Period(object): 779 # TODO: Not implemented yet 780 pass 781 782 783class PeriodFactory(object): 784 # TODO: Not implemented yet 785 786 def parse(self, data, message_info): 787 raise NotImplementedError("TODO: Not implemented yet") 788 789 790# ScanDuration TLV (56) 791class ScanDuration(object): 792 # TODO: Not implemented yet 793 pass 794 795 796class ScanDurationFactory(object): 797 # TODO: Not implemented yet 798 799 def parse(self, data, message_info): 800 raise NotImplementedError("TODO: Not implemented yet") 801 802 803# EnergyList TLV (57) 804class EnergyList(object): 805 # TODO: Not implemented yet 806 pass 807 808 809class EnergyListFactory(object): 810 # TODO: Not implemented yet 811 812 def parse(self, data, message_info): 813 raise NotImplementedError("TODO: Not implemented yet") 814 815 816# Discovery Request TLV (128) 817class DiscoveryRequest(object): 818 819 def __init__(self, version, joiner_flag): 820 self._version = version 821 self._joiner_flag = joiner_flag 822 823 @property 824 def version(self): 825 return self._version 826 827 @property 828 def joiner_flag(self): 829 return self._joiner_flag 830 831 def __eq__(self, other): 832 return (isinstance(self, type(other)) and self.version == other.version and 833 self.joiner_flag == other.joiner_flag) 834 835 def __repr__(self): 836 return "DiscoveryRequest(version={}, joiner_flag={})".format(self.version, self.joiner_flag) 837 838 839class DiscoveryRequestFactory(object): 840 841 def parse(self, data, message_info): 842 data_byte = struct.unpack(">B", data.read(1))[0] 843 version = (data_byte & 0xf0) >> 4 844 joiner_flag = (data_byte & 0x08) >> 3 845 846 return DiscoveryRequest(version, joiner_flag) 847 848 849# Discovery Response TLV (128) 850class DiscoveryResponse(object): 851 852 def __init__(self, version, native_flag): 853 self._version = version 854 self._native_flag = native_flag 855 856 @property 857 def version(self): 858 return self._version 859 860 @property 861 def native_flag(self): 862 return self._native_flag 863 864 def __eq__(self, other): 865 return (isinstance(self, type(other)) and self.version == other.version and 866 self.native_flag == other.native_flag) 867 868 def __repr__(self): 869 return "DiscoveryResponse(version={}, native_flag={})".format(self.version, self.native_flag) 870 871 872class DiscoveryResponseFactory(object): 873 874 def parse(self, data, message_info): 875 data_byte = struct.unpack(">B", data.read(1))[0] 876 version = (data_byte & 0xf0) >> 4 877 native_flag = (data_byte & 0x08) >> 3 878 879 return DiscoveryResponse(version, native_flag) 880 881 882class MeshCopCommand(object): 883 884 def __init__(self, _type, tlvs): 885 self._type = _type 886 self._tlvs = tlvs 887 888 @property 889 def type(self): 890 return self._type 891 892 @property 893 def tlvs(self): 894 return self._tlvs 895 896 def __repr__(self): 897 tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.tlvs]) 898 return "MeshCopCommand(type={}, tlvs=[{}])".format(self.type, tlvs_str) 899 900 901def create_deault_mesh_cop_msg_type_map(): 902 return { 903 'JOIN_FIN.req': MeshCopMessageType.JOIN_FIN_REQ, 904 'JOIN_FIN.rsp': MeshCopMessageType.JOIN_FIN_RSP, 905 'JOIN_ENT.ntf': MeshCopMessageType.JOIN_ENT_NTF, 906 'JOIN_ENT.rsp': MeshCopMessageType.JOIN_ENT_RSP, 907 } 908 909 910class MeshCopCommandFactory: 911 912 def __init__(self, tlvs_factories): 913 self._tlvs_factories = tlvs_factories 914 self._mesh_cop_msg_type_map = create_deault_mesh_cop_msg_type_map() 915 916 def _get_length(self, data): 917 return ord(data.read(1)) 918 919 def _get_tlv_factory(self, _type): 920 try: 921 return self._tlvs_factories[_type] 922 except KeyError: 923 logging.error('Could not find TLV factory. Unsupported TLV type: {}'.format(_type)) 924 return UnknownTlvFactory(_type) 925 926 def _parse_tlv(self, data): 927 _type = TlvType(ord(data.read(1))) 928 length = self._get_length(data) 929 value = data.read(length) 930 factory = self._get_tlv_factory(_type) 931 return factory.parse(io.BytesIO(value), None) # message_info not needed here 932 933 def _get_mesh_cop_msg_type(self, msg_type_str): 934 try: 935 return self._mesh_cop_msg_type_map[msg_type_str] 936 except KeyError: 937 raise KeyError('Mesh cop message type not found: {}'.format(msg_type_str)) 938 939 def parse(self, cmd_type_str, data): 940 cmd_type = self._get_mesh_cop_msg_type(cmd_type_str) 941 942 tlvs = [] 943 while data.tell() < len(data.getvalue()): 944 tlv = self._parse_tlv(data) 945 tlvs.append(tlv) 946 947 return MeshCopCommand(cmd_type, tlvs) 948 949 950def create_default_mesh_cop_tlv_factories(): 951 return { 952 TlvType.STATE: StateFactory(), 953 TlvType.PROVISIONING_URL: ProvisioningUrlFactory(), 954 TlvType.VENDOR_NAME: VendorNameFactory(), 955 TlvType.VENDOR_MODEL: VendorModelFactory(), 956 TlvType.VENDOR_SW_VERSION: VendorSWVersionFactory(), 957 TlvType.VENDOR_DATA: VendorDataFactory(), 958 TlvType.VENDOR_STACK_VERSION: VendorStackVersionFactory(), 959 } 960 961 962class ThreadDiscoveryTlvsFactory(SubTlvsFactory): 963 964 def __init__(self, sub_tlvs_factories): 965 super(ThreadDiscoveryTlvsFactory, self).__init__(sub_tlvs_factories) 966