• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#  Copyright (c) 2020, 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#
29import ipaddress
30from collections import namedtuple
31
32
33class ChildId(int):
34    """Represents a Child ID."""
35    pass
36
37
38class RouterId(int):
39    """Represents a Router ID."""
40    pass
41
42
43class Rloc16(int):
44    """Represents a RLOC16."""
45
46    def __repr__(self):
47        return '0x%04x' % self
48
49
50class PartitionId(int):
51    """Represents a Thread Network Partition ID."""
52    pass
53
54
55class NetifIdentifier(int):
56    """Represents a network interface identifier."""
57    UNSPECIFIED = 0
58    THERAD = 1
59    BACKBONE = 2
60
61
62class DeviceMode(str):
63    """Represents a device mode."""
64
65    def __new__(cls, o: str):
66        ins = str.__new__(cls, o)
67
68        if ins != '-':
69            for c in ins:
70                if c not in 'rdn':
71                    raise ValueError(o)
72
73        # check for empty mode (SED should use "-")
74        if not ins:
75            raise ValueError(o)
76
77        # check for duplicate chars
78        if len(ins) != len(set(ins)):
79            raise ValueError(o)
80
81        return ins
82
83
84class ThreadState(str):
85    """Represents a Thread state."""
86    _VALID_VALUES = {'disabled', 'detached', 'child', 'router', 'leader'}
87
88    def __new__(cls, o: str):
89        ins = str.__new__(cls, o)
90
91        if ins not in ThreadState._VALID_VALUES:
92            raise ValueError(o)
93
94        return ins
95
96
97class Ip6Addr(ipaddress.IPv6Address):
98    """Represents an IPv6 address."""
99
100    def __eq__(self, other):
101        if isinstance(other, str):
102            other = ipaddress.IPv6Address(other)
103
104        return super().__eq__(other)
105
106    def __repr__(self):
107        return self.compressed
108
109    def __hash__(self):
110        return super().__hash__()
111
112
113class Ip6Prefix(ipaddress.IPv6Network):
114    """Represents an IPv6 prefix."""
115
116    def __eq__(self, other):
117        if isinstance(other, str):
118            other = ipaddress.IPv6Network(other)
119
120        return super().__eq__(other)
121
122    def __repr__(self):
123        return self.compressed
124
125    def __hash__(self):
126        return super().__hash__()
127
128
129SecurityPolicy = namedtuple('SecurityPolicy', ['rotation_time', 'flags'])
130"""Represents a Security Policy configuration."""
131
132
133class RouterTableEntry(dict):
134
135    @property
136    def is_link_established(self):
137        return bool(self['link'])
138
139
140if __name__ == '__main__':
141    assert Ip6Addr('2001:0:0:0:0:0:0:1') == '2001::1'
142    assert repr(Ip6Addr('2001:0:0:0:0:0:0:1')) == '2001::1'
143    assert str(Ip6Addr('2001:0:0:0:0:0:0:1')) == '2001::1'
144    assert Ip6Prefix('2001:0:0:0::/64') == '2001::/64'
145    assert repr(Ip6Prefix('2001:0:0:0::/64')) == '2001::/64'
146    assert str(Ip6Prefix('2001:0:0:0::/64')) == '2001::/64'
147