| #!/usr/bin/env python | |
| # | |
| # Copyright (c) 2016, The OpenThread Authors. | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are met: | |
| # 1. Redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer. | |
| # 2. Redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution. | |
| # 3. Neither the name of the copyright holder nor the | |
| # names of its contributors may be used to endorse or promote products | |
| # derived from this software without specific prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
| # POSSIBILITY OF SUCH DAMAGE. | |
| # | |
| import struct | |
| import sys | |
| from binascii import hexlify | |
| from enum import IntEnum | |
| import ipaddress | |
| def expect_the_same_class(self, other): | |
| if not isinstance(other, self.__class__): | |
| raise TypeError("Expected the same class. Got {} and {}".format(type(self), type(other))) | |
| class MessageInfo(object): | |
| def __init__(self): | |
| self.aux_sec_hdr = None | |
| self.aux_sec_hdr_bytes = None | |
| self.mhr_bytes = None | |
| self.nonpayload_fields = None | |
| self.source_mac_address = None | |
| self.destination_mac_address = None | |
| self._source_ipv6 = None | |
| self._destination_ipv6 = None | |
| self._src_port = None | |
| self._dst_port = None | |
| self.stable = None | |
| self.payload_length = 0 | |
| def _convert_value_to_ip_address(self, value): | |
| if isinstance(value, bytearray): | |
| value = bytes(value) | |
| elif isinstance(value, str) and sys.version_info[0] == 2: | |
| value = value.decode("utf-8") | |
| return ipaddress.ip_address(value) | |
| @property | |
| def source_ipv6(self): | |
| return self._source_ipv6 | |
| @source_ipv6.setter | |
| def source_ipv6(self, value): | |
| self._source_ipv6 = self._convert_value_to_ip_address(value) | |
| @property | |
| def destination_ipv6(self): | |
| return self._destination_ipv6 | |
| @destination_ipv6.setter | |
| def destination_ipv6(self, value): | |
| self._destination_ipv6 = self._convert_value_to_ip_address(value) | |
| @property | |
| def src_port(self): | |
| return self._src_port | |
| @src_port.setter | |
| def src_port(self, value): | |
| self._src_port = value | |
| @property | |
| def dst_port(self): | |
| return self._dst_port | |
| @dst_port.setter | |
| def dst_port(self, value): | |
| self._dst_port = value | |
| class MacAddressType(IntEnum): | |
| SHORT = 0 | |
| LONG = 1 | |
| class MacAddress(object): | |
| def __init__(self, mac_address, _type, big_endian=True): | |
| if _type == MacAddressType.SHORT: | |
| length = 2 | |
| elif _type == MacAddressType.LONG: | |
| length = 8 | |
| if not big_endian: | |
| mac_address = mac_address[::-1] | |
| self._mac_address = bytearray(mac_address[:length]) | |
| self._type = _type | |
| @property | |
| def type(self): | |
| return self._type | |
| @property | |
| def mac_address(self): | |
| return self._mac_address | |
| @property | |
| def rloc(self): | |
| return struct.unpack(">H", self._mac_address)[0] | |
| def convert_to_iid(self): | |
| if self._type == MacAddressType.SHORT: | |
| return bytearray([0x00, 0x00, 0x00, 0xff, 0xfe, 0x00]) + self._mac_address[:2] | |
| elif self._type == MacAddressType.LONG: | |
| return bytearray([self._mac_address[0] ^ 0x02]) + self._mac_address[1:] | |
| else: | |
| raise RuntimeError("Could not convert to IID. Invalid MAC address type: {}".format(self._type)) | |
| @classmethod | |
| def from_eui64(cls, eui64, big_endian=True): | |
| if not isinstance(eui64, bytearray): | |
| raise RuntimeError("Could not create MAC address from EUI64. Invalid data type: {}".format(type(eui64))) | |
| return cls(eui64, MacAddressType.LONG) | |
| @classmethod | |
| def from_rloc16(cls, rloc16, big_endian=True): | |
| if isinstance(rloc16, int): | |
| mac_address = struct.pack(">H", rloc16) | |
| elif isinstance(rloc16, bytearray): | |
| mac_address = rloc16[:2] | |
| else: | |
| raise RuntimeError("Could not create MAC address from RLOC16. Invalid data type: {}".format(type(rloc16))) | |
| return cls(mac_address, MacAddressType.SHORT) | |
| def __eq__(self, other): | |
| return (self.type == other.type) and (self.mac_address == other.mac_address) | |
| def __repr__(self): | |
| return "MacAddress(mac_address=b'{}', type={})".format(hexlify(self.mac_address), MacAddressType(self._type)) |