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 math
32import struct
33
34from binascii import hexlify
35from enum import IntEnum
36from tlvs_parsing import SubTlvsFactory
37
38import common
39
40
41class TlvType(IntEnum):
42    HAS_ROUTE = 0
43    PREFIX = 1
44    BORDER_ROUTER = 2
45    LOWPAN_ID = 3
46    COMMISSIONING = 4
47    SERVICE = 5
48    SERVER = 6
49
50
51class NetworkData(object):
52
53    def __init__(self, stable):
54        self._stable = stable
55
56    @property
57    def stable(self):
58        return self._stable
59
60
61class NetworkDataSubTlvsFactory(SubTlvsFactory):
62
63    def parse(self, data, message_info):
64        sub_tlvs = []
65
66        while data.tell() < len(data.getvalue()):
67            data_byte = ord(data.read(1))
68
69            stable = data_byte & 0x01
70            _type = (data_byte >> 1) & 0x7F
71
72            length = ord(data.read(1))
73            value = data.read(length)
74
75            factory = self._get_factory(_type)
76
77            message_info.stable = stable
78            tlv = factory.parse(io.BytesIO(value), message_info)
79
80            sub_tlvs.append(tlv)
81
82        return sub_tlvs
83
84
85class Route(object):
86
87    def __init__(self, border_router_16, prf):
88        self._border_router_16 = border_router_16
89        self._prf = prf
90
91    @property
92    def border_router_16(self):
93        return self._border_router_16
94
95    @property
96    def prf(self):
97        return self._prf
98
99    def __eq__(self, other):
100        common.expect_the_same_class(self, other)
101
102        return (self.border_router_16 == other.border_router_16 and self.prf == other.prf)
103
104    def __repr__(self):
105        return "Route(border_router_16={}, prf={})".format(self.border_router_16, self.prf)
106
107
108class RouteFactory(object):
109
110    def parse(self, data, message_info):
111        border_router_16 = struct.unpack(">H", data.read(2))[0]
112
113        data_byte = ord(data.read(1))
114        prf = (data_byte >> 6) & 0x03
115
116        return Route(border_router_16, prf)
117
118
119class RoutesFactory(object):
120
121    def __init__(self, route_factory):
122        self._route_factory = route_factory
123
124    def parse(self, data, message_info):
125        routes = []
126
127        while data.tell() < len(data.getvalue()):
128            route = self._route_factory.parse(data, message_info)
129
130            routes.append(route)
131
132        return routes
133
134
135class HasRoute(NetworkData):
136
137    def __init__(self, routes, stable):
138        super(HasRoute, self).__init__(stable)
139        self._routes = routes
140
141    @property
142    def routes(self):
143        return self._routes
144
145    def __eq__(self, other):
146        common.expect_the_same_class(self, other)
147
148        return self.routes == other.routes
149
150    def __repr__(self):
151        routes_str = ", ".join(["{}".format(route) for route in self.routes])
152        return "HasRoute(stable={}, routes=[{}])".format(self.stable, routes_str)
153
154
155class HasRouteFactory(object):
156
157    def __init__(self, routes_factory):
158        self._routes_factory = routes_factory
159
160    def parse(self, data, message_info):
161        routes = self._routes_factory.parse(data, message_info)
162
163        return HasRoute(routes, message_info.stable)
164
165
166class Prefix(NetworkData):
167
168    def __init__(self, domain_id, prefix_length, prefix, sub_tlvs, stable):
169        super(Prefix, self).__init__(stable)
170        self._domain_id = domain_id
171        self._prefix_length = prefix_length
172        self._prefix = prefix
173        self._sub_tlvs = sub_tlvs
174
175    @property
176    def domain_id(self):
177        return self._domain_id
178
179    @property
180    def prefix_length(self):
181        return self._prefix_length
182
183    @property
184    def prefix(self):
185        return self._prefix
186
187    @property
188    def sub_tlvs(self):
189        return self._sub_tlvs
190
191    def __eq__(self, other):
192        common.expect_the_same_class(self, other)
193
194        return (self.domain_id == other.domain_id and self.prefix_length == other.prefix_length and
195                self.prefix == other.prefix and self.sub_tlvs == other.sub_tlvs)
196
197    def __repr__(self):
198        sub_tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.sub_tlvs])
199        return "Prefix(stable={}, domain_id={}, prefix_length={}, prefix={}, sub_tlvs=[{}])".format(
200            self.stable,
201            self.domain_id,
202            self.prefix_length,
203            hexlify(self.prefix),
204            sub_tlvs_str,
205        )
206
207
208class PrefixSubTlvsFactory(NetworkDataSubTlvsFactory):
209
210    def __init__(self, sub_tlvs_factories):
211        super(PrefixSubTlvsFactory, self).__init__(sub_tlvs_factories)
212
213
214class PrefixFactory(object):
215
216    def __init__(self, sub_tlvs_factory):
217        self._sub_tlvs_factory = sub_tlvs_factory
218
219    def _bits_to_bytes(self, bits):
220        return int(math.ceil(bits / 8))
221
222    def parse(self, data, message_info):
223        domain_id = ord(data.read(1))
224
225        prefix_length = ord(data.read(1))
226
227        prefix = bytearray(data.read(self._bits_to_bytes(prefix_length)))
228
229        sub_tlvs = self._sub_tlvs_factory.parse(io.BytesIO(data.read()), message_info)
230
231        return Prefix(domain_id, prefix_length, prefix, sub_tlvs, message_info.stable)
232
233
234class BorderRouter(NetworkData):
235
236    def __init__(self, border_router_16, prf, p, s, d, c, r, o, n, stable):
237        super(BorderRouter, self).__init__(stable)
238        self._border_router_16 = border_router_16
239        self._prf = prf
240        self._p = p
241        self._s = s
242        self._d = d
243        self._c = c
244        self._r = r
245        self._o = o
246        self._n = n
247
248    @property
249    def border_router_16(self):
250        return self._border_router_16
251
252    @property
253    def prf(self):
254        return self._prf
255
256    @property
257    def p(self):
258        return self._p
259
260    @property
261    def s(self):
262        return self._s
263
264    @property
265    def d(self):
266        return self._d
267
268    @property
269    def c(self):
270        return self._c
271
272    @property
273    def r(self):
274        return self._r
275
276    @property
277    def o(self):
278        return self._o
279
280    @property
281    def n(self):
282        return self._n
283
284    def __eq__(self, other):
285        common.expect_the_same_class(self, other)
286
287        return (self.border_router_16 == other.border_router_16 and self.prf == other.prf and self.p == other.p and
288                self.s == other.s and self.d == other.d and self.c == other.c and self.r == other.r and
289                self.o == other.o and self.n == other.n)
290
291    def __repr__(self):
292        return "BorderRouter(stable={}, border_router_16={}, prf={}, p={}, s={}, d={}, c={}, r={}, o={}, n={})".format(
293            self.stable,
294            self.border_router_16,
295            self.prf,
296            self.p,
297            self.s,
298            self.d,
299            self.c,
300            self.r,
301            self.o,
302            self.n,
303        )
304
305
306class BorderRouterFactory(object):
307
308    def parse(self, data, message_info):
309        border_router_16 = struct.unpack(">H", data.read(2))[0]
310
311        data_byte = ord(data.read(1))
312        o = data_byte & 0x01
313        r = (data_byte >> 1) & 0x01
314        c = (data_byte >> 2) & 0x01
315        d = (data_byte >> 3) & 0x01
316        s = (data_byte >> 4) & 0x01
317        p = (data_byte >> 5) & 0x01
318        prf = (data_byte >> 6) & 0x03
319
320        data_byte = ord(data.read(1))
321        n = (data_byte >> 7) & 0x01
322
323        return BorderRouter(border_router_16, prf, p, s, d, c, r, o, n, message_info.stable)
324
325
326class LowpanId(NetworkData):
327
328    def __init__(self, c, cid, context_length, stable):
329        super(LowpanId, self).__init__(stable)
330        self._c = c
331        self._cid = cid
332        self._context_length = context_length
333
334    @property
335    def c(self):
336        return self._c
337
338    @property
339    def cid(self):
340        return self._cid
341
342    @property
343    def context_length(self):
344        return self._context_length
345
346    def __eq__(self, other):
347        common.expect_the_same_class(self, other)
348
349        return (self.c == other.c and self.cid == other.cid and self.context_length == other.context_length)
350
351    def __repr__(self):
352        return "LowpanId(stable={}, c={}, cid={}, context_length={})".format(self.stable, self.c, self.cid,
353                                                                             self.context_length)
354
355
356class LowpanIdFactory(object):
357
358    def parse(self, data, message_info):
359        data_byte = ord(data.read(1))
360
361        cid = data_byte & 0x0F
362        c = (data_byte >> 4) & 0x01
363
364        context_length = ord(data.read(1))
365
366        return LowpanId(c, cid, context_length, message_info.stable)
367
368
369class CommissioningData(NetworkData):
370
371    def __init__(self, sub_tlvs, stable):
372        super(CommissioningData, self).__init__(stable)
373        self._sub_tlvs = sub_tlvs
374
375    @property
376    def sub_tlvs(self):
377        return self._sub_tlvs
378
379    def __eq__(self, other):
380        common.expect_the_same_class(self, other)
381
382        return self.sub_tlvs == other.sub_tlvs
383
384    def __repr__(self):
385        sub_tlvs_str = ", ".join(["{}".format(tlv) for tlv in self._sub_tlvs])
386        return "CommissioningData(stable={}, sub_tlvs=[{}])".format(self._stable, sub_tlvs_str)
387
388
389class CommissioningDataSubTlvsFactory(SubTlvsFactory):
390
391    def __init__(self, sub_tlvs_factories):
392        super(CommissioningDataSubTlvsFactory, self).__init__(sub_tlvs_factories)
393
394
395class CommissioningDataFactory(object):
396
397    def __init__(self, sub_tlvs_factory):
398        self._sub_tlvs_factory = sub_tlvs_factory
399
400    def parse(self, data, message_info):
401        sub_tlvs = self._sub_tlvs_factory.parse(io.BytesIO(data.read()), message_info)
402
403        return CommissioningData(sub_tlvs, message_info.stable)
404
405
406class Service(NetworkData):
407
408    def __init__(
409        self,
410        t,
411        _id,
412        enterprise_number,
413        service_data_length,
414        service_data,
415        sub_tlvs,
416        stable,
417    ):
418        super(Service, self).__init__(stable)
419        self._t = t
420        self._id = _id
421        self._enterprise_number = enterprise_number
422        self._service_data_length = service_data_length
423        self._service_data = service_data
424        self._sub_tlvs = sub_tlvs
425
426    @property
427    def t(self):
428        return self._t
429
430    @property
431    def id(self):
432        return self._id
433
434    @property
435    def enterprise_number(self):
436        return self._enterprise_number
437
438    @property
439    def service_data_length(self):
440        return self._service_data_length
441
442    @property
443    def service_data(self):
444        return self._service_data
445
446    @property
447    def sub_tlvs(self):
448        return self._sub_tlvs
449
450    def __eq__(self, other):
451        common.expect_the_same_class(self, other)
452
453        return (self.t == other.t and self.id == other.id and self.enterprise_number == other.enterprise_number and
454                self.service_data_length == other.service_data_length and self.service_data == other.service_data and
455                self.sub_tlvs == other.sub_tlvs)
456
457    def __repr__(self):
458        sub_tlvs_str = ", ".join(["{}".format(tlv) for tlv in self.sub_tlvs])
459        return (
460            "LowpanId(stable={}, t={}, id={}, enterprise_number={}, service_data_length={}, service_data={}, sub_tlvs=[{}])"
461        ).format(
462            self.stable,
463            self.t,
464            self.id,
465            self.enterprise_number,
466            self.service_data_length,
467            self.service_data,
468            sub_tlvs_str,
469        )
470
471
472class ServiceSubTlvsFactory(NetworkDataSubTlvsFactory):
473
474    def __init__(self, sub_tlvs_factories):
475        super(ServiceSubTlvsFactory, self).__init__(sub_tlvs_factories)
476
477
478class ServiceFactory(object):
479
480    def __init__(self, sub_tlvs_factory):
481        self._sub_tlvs_factory = sub_tlvs_factory
482
483    def parse(self, data, message_info):
484        data_byte = ord(data.read(1))
485        t = (data_byte >> 7) & 0x01
486        _id = data_byte & 0x0F
487
488        enterprise_number = struct.unpack(">L", data.read(4))[0]
489        service_data_length = ord(data.read(1))
490        service_data = data.read(service_data_length)
491
492        sub_tlvs = self._sub_tlvs_factory.parse(io.BytesIO(data.read()), message_info)
493
494        return Service(
495            t,
496            _id,
497            enterprise_number,
498            service_data_length,
499            service_data,
500            sub_tlvs,
501            message_info.stable,
502        )
503
504
505class Server(NetworkData):
506
507    def __init__(self, server_16, server_data, stable):
508        super(Server, self).__init__(stable)
509        self._server_16 = server_16
510        self._server_data = server_data
511
512    @property
513    def server_16(self):
514        return self._server_16
515
516    @property
517    def server_data(self):
518        return self._server_data
519
520    def __eq__(self, other):
521        common.expect_the_same_class(self, other)
522
523        return (self.server_16 == other.server_16 and self.server_data == other.server_data)
524
525    def __repr__(self):
526        return "LowpanId(stable={}, server_16={}, server_data=b'{}')".format(self.stable, self.server_16,
527                                                                             hexlify(self.server_data))
528
529
530class ServerFactory(object):
531
532    def parse(self, data, message_info):
533        server_16 = struct.unpack(">H", data.read(2))[0]
534        server_data = bytearray(data.read())
535
536        return Server(server_16, server_data, message_info.stable)
537
538
539class NetworkDataTlvsFactory(NetworkDataSubTlvsFactory):
540
541    def __init__(self, sub_tlvs_factories):
542        super(NetworkDataTlvsFactory, self).__init__(sub_tlvs_factories)
543