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