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# 29import datetime 30import sys 31import time 32from typing import Any, Union 33 34from pyshark.packet.fields import LayerFieldsContainer, LayerField 35from pyshark.packet.packet import Packet as RawPacket 36 37from pktverify.addrs import EthAddr, ExtAddr, Ipv6Addr 38from pktverify.bytes import Bytes 39from pktverify.consts import VALID_LAYER_NAMES 40from pktverify.null_field import nullField 41 42 43def _auto(v: Union[LayerFieldsContainer, LayerField]): 44 """parse the layer field automatically according to its format""" 45 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 or v.get_default_value() is not None, v.fields 46 dv = v.get_default_value() 47 rv = v.raw_value 48 49 if dv.startswith('0x'): 50 return int(dv, 16) 51 52 try: 53 if dv == rv: 54 return int(dv) 55 elif int(dv) == int(rv, 16): 56 return int(dv) 57 except (ValueError, TypeError): 58 pass 59 60 if rv is None: 61 try: 62 return int(dv) 63 except (ValueError, TypeError): 64 pass 65 66 if ':' in dv and '::' not in dv and dv.replace(':', '') == rv: # '88:00', '8800' 67 return int(rv, 16) 68 69 # timestamp: 'Jan 1, 1970 08:00:00.000000000 CST', '0000000000000000' 70 # convert to seconds from 1970, ignore the nanosecond for now since 71 # there are integer seconds applied in the test cases 72 try: 73 time_str = datetime.datetime.strptime(dv, "%b %d, %Y %H:%M:%S.%f000 %Z") 74 time_in_sec = time.mktime(time_str.utctimetuple()) 75 return int(time_in_sec) 76 except (ValueError, TypeError): 77 pass 78 79 try: 80 int(rv, 16) 81 return int(dv) 82 except Exception: 83 pass 84 85 raise ValueError((v, v.get_default_value(), v.raw_value)) 86 87 88def _payload(v: Union[LayerFieldsContainer, LayerField]) -> bytearray: 89 """parse the layer field as a bytearray""" 90 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 91 hex_value = v.raw_value 92 assert len(hex_value) % 2 == 0 93 s = bytearray() 94 for i in range(0, len(hex_value), 2): 95 s.append(int(hex_value[i:i + 2], 16)) 96 97 return s 98 99 100def _hex(v: Union[LayerFieldsContainer, LayerField]) -> int: 101 """parse the layer field as a hex string""" 102 # split v into octets and reverse the order 103 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 104 return int(v.get_default_value(), 16) 105 106 107def _raw_hex(v: Union[LayerFieldsContainer, LayerField]) -> int: 108 """parse the layer field as a raw hex string""" 109 # split v into octets and reverse the order 110 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 111 iv = v.hex_value 112 113 try: 114 int(v.get_default_value()) 115 assert int(v.get_default_value()) == iv, (v.get_default_value(), v.raw_value) 116 except ValueError: 117 pass 118 119 try: 120 int(v.get_default_value(), 16) 121 assert int(v.get_default_value(), 16) == iv, (v.get_default_value(), v.raw_value) 122 except ValueError: 123 pass 124 125 return iv 126 127 128def _raw_hex_rev(v: Union[LayerFieldsContainer, LayerField]) -> int: 129 """parse the layer field as a reversed raw hex string""" 130 # split v into octets and reverse the order 131 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 132 rv = v.raw_value 133 octets = [rv[i:i + 2] for i in range(0, len(rv), 2)] 134 135 iv = int(''.join(reversed(octets)), 16) 136 137 try: 138 int(v.get_default_value()) 139 assert int(v.get_default_value()) == iv, (v.get_default_value(), v.raw_value) 140 except ValueError: 141 pass 142 143 try: 144 int(v.get_default_value(), 16) 145 assert int(v.get_default_value(), 16) == iv, (v.get_default_value(), v.raw_value) 146 except ValueError: 147 pass 148 149 return iv 150 151 152def _dec(v: Union[LayerFieldsContainer, LayerField]) -> int: 153 """parse the layer field as a decimal""" 154 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 155 return int(v.get_default_value()) 156 157 158def _float(v: Union[LayerFieldsContainer, LayerField]) -> float: 159 """parse the layer field as a float""" 160 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 161 return float(v.get_default_value()) 162 163 164def _str(v: Union[LayerFieldsContainer, LayerField]) -> str: 165 """parse the layer field as a string""" 166 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 167 return str(v.get_default_value()) 168 169 170def _bytes(v: Union[LayerFieldsContainer, LayerField]) -> Bytes: 171 """parse the layer field as raw bytes""" 172 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 173 return Bytes(v.raw_value) 174 175 176def _ext_addr(v: Union[LayerFieldsContainer, LayerField]) -> ExtAddr: 177 """parse the layer field as an extended address""" 178 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 179 return ExtAddr(v.get_default_value()) 180 181 182def _ipv6_addr(v: Union[LayerFieldsContainer, LayerField]) -> Ipv6Addr: 183 """parse the layer field as an IPv6 address""" 184 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 185 return Ipv6Addr(v.get_default_value()) 186 187 188def _eth_addr(v: Union[LayerFieldsContainer, LayerField]) -> EthAddr: 189 """parse the layer field as an Ethernet MAC address""" 190 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1, v.fields 191 return EthAddr(v.get_default_value()) 192 193 194def _routerid_set(v: Union[LayerFieldsContainer, LayerField]) -> set: 195 """parse the layer field as a set of router ids 196 197 Notes: the router ID mask in wireshark is a 198 hexadecimal string separated by ':' 199 """ 200 assert not isinstance(v, LayerFieldsContainer) or len(v.fields) == 1 201 202 try: 203 ridmask = str(v.get_default_value()) 204 assert isinstance(ridmask, str), ridmask 205 ridmask_int = int(ridmask.replace(':', ''), base=16) 206 rid_set = set() 207 count = 0 208 while ridmask_int: 209 count += 1 210 if ridmask_int & 1: 211 rid_set.add(64 - count) 212 ridmask_int = ridmask_int >> 1 213 except ValueError: 214 pass 215 216 return rid_set 217 218 219class _first(object): 220 """parse the first layer field""" 221 222 def __init__(self, sub_parse): 223 self._sub_parse = sub_parse 224 225 def __call__(self, v: Union[LayerFieldsContainer, LayerField]): 226 return self._sub_parse(v.fields[0]) 227 228 229class _list(object): 230 """parse all layer fields into a list""" 231 232 def __init__(self, sub_parse): 233 self._sub_parse = sub_parse 234 235 def __call__(self, v: Union[LayerFieldsContainer, LayerField]): 236 return [self._sub_parse(f) for f in v.fields] 237 238 239_LAYER_FIELDS = { 240 # WPAN 241 'wpan.fcf': _raw_hex_rev, 242 'wpan.cmd': _auto, 243 'wpan.security': _auto, 244 'wpan.frame_type': _auto, 245 'wpan.pending': _auto, 246 'wpan.ack_request': _auto, 247 'wpan.pan_id_compression': _auto, 248 'wpan.seqno_suppression': _auto, 249 'wpan.ie_present': _auto, 250 'wpan.dst_addr_mode': _auto, 251 'wpan.version': _auto, 252 'wpan.src_addr_mode': _auto, 253 'wpan.dst_pan': _auto, 254 'wpan.seq_no': _auto, 255 'wpan.src16': _auto, 256 'wpan.dst16': _auto, 257 'wpan.src64': _ext_addr, 258 'wpan.dst64': _ext_addr, 259 'wpan.fcs': _raw_hex_rev, 260 'wpan.fcs_ok': _auto, 261 'wpan.frame_length': _dec, 262 'wpan.key_number': _auto, 263 'wpan.aux_sec.sec_suite': _auto, 264 'wpan.aux_sec.security_control_field': _auto, 265 'wpan.aux_sec.sec_level': _auto, 266 'wpan.aux_sec.key_id_mode': _auto, 267 'wpan.aux_sec.frame_counter_suppression': _auto, 268 'wpan.aux_sec.asn_in_nonce': _auto, 269 'wpan.aux_sec.reserved': _auto, 270 'wpan.aux_sec.frame_counter': _auto, 271 'wpan.aux_sec.key_source': _auto, 272 'wpan.aux_sec.key_index': _auto, 273 'wpan.aux_sec.hdr': _str, 274 'wpan.mic': _auto, 275 'wpan.channel': _auto, 276 'wpan.header_ie.id': _list(_auto), 277 'wpan.header_ie.csl.period': _auto, 278 'wpan.payload_ie.vendor.oui': _auto, 279 280 # MLE 281 'mle.cmd': _auto, 282 'mle.sec_suite': _hex, 283 'mle.tlv.type': _list(_dec), 284 'mle.tlv.len': _list(_dec), 285 'mle.tlv.mode.receiver_on_idle': _auto, 286 'mle.tlv.mode.reserved1': _auto, 287 'mle.tlv.mode.reserved2': _auto, 288 'mle.tlv.mode.device_type_bit': _auto, 289 'mle.tlv.mode.network_data': _auto, 290 'mle.tlv.challenge': _bytes, 291 'mle.tlv.scan_mask.r': _auto, 292 'mle.tlv.scan_mask.e': _auto, 293 'mle.tlv.version': _auto, 294 'mle.tlv.source_addr': _auto, 295 'mle.tlv.active_tstamp': _auto, 296 'mle.tlv.pending_tstamp': _auto, 297 'mle.tlv.leader_data.partition_id': _auto, 298 'mle.tlv.leader_data.weighting': _auto, 299 'mle.tlv.leader_data.data_version': _auto, 300 'mle.tlv.leader_data.stable_data_version': _auto, 301 'mle.tlv.leader_data.router_id': _auto, 302 'mle.tlv.route64.nbr_out': _list(_auto), 303 'mle.tlv.route64.nbr_in': _list(_auto), 304 'mle.tlv.route64.id_seq': _auto, 305 'mle.tlv.route64.id_mask': _routerid_set, 306 'mle.tlv.route64.cost': _list(_auto), 307 'mle.tlv.response': _bytes, 308 'mle.tlv.mle_frm_cntr': _auto, 309 'mle.tlv.ll_frm_cntr': _auto, 310 'mle.tlv.link_margin': _auto, 311 'mle.tlv.conn.sed_dgram_cnt': _auto, 312 'mle.tlv.conn.sed_buf_size': _auto, 313 'mle.tlv.conn.lq3': _auto, 314 'mle.tlv.conn.lq2': _auto, 315 'mle.tlv.conn.lq1': _auto, 316 'mle.tlv.conn.leader_cost': _auto, 317 'mle.tlv.conn.id_seq': _auto, 318 'mle.tlv.conn.flags.pp': _auto, 319 'mle.tlv.conn.active_rtrs': _auto, 320 'mle.tlv.timeout': _auto, 321 'mle.tlv.addr16': _auto, 322 'mle.tlv.channel': _auto, 323 'mle.tlv.addr_reg_iid': _list(_auto), 324 'mle.tlv.link_enh_ack_flags': _auto, 325 'mle.tlv.link_forward_series': _list(_auto), 326 'mle.tlv.link_requested_type_id_flags': _list(_hex), 327 'mle.tlv.link_sub_tlv': _auto, 328 'mle.tlv.link_status_sub_tlv': _auto, 329 'mle.tlv.query_id': _auto, 330 'mle.tlv.metric_type_id_flags.type': _list(_hex), 331 'mle.tlv.metric_type_id_flags.metric': _list(_hex), 332 'mle.tlv.metric_type_id_flags.l': _list(_hex), 333 'mle.tlv.link_requested_type_id_flags': _bytes, 334 335 # IP 336 'ip.version': _auto, 337 'ip.src': _str, 338 'ip.src_host': _str, 339 'ip.dst': _str, 340 'ip.dst_host': _str, 341 'ip.ttl': _auto, 342 'ip.proto': _auto, 343 'ip.len': _auto, 344 'ip.id': _auto, 345 'ip.host': _list(_str), 346 'ip.hdr_len': _dec, 347 'ip.frag_offset': _auto, 348 'ip.flags.rb': _auto, 349 'ip.flags.mf': _auto, 350 'ip.flags.df': _auto, 351 'ip.dsfield.ecn': _auto, 352 'ip.dsfield.dscp': _auto, 353 'ip.checksum.status': _auto, 354 'ip.addr': _list(_str), 355 'ip.options.routeralert': _bytes, 356 'ip.opt.type.number': _auto, 357 'ip.opt.type.copy': _auto, 358 'ip.opt.type.class': _auto, 359 'ip.opt.ra': _auto, 360 'ip.opt.len': _auto, 361 # UDP 362 'udp.stream': _auto, 363 'udp.srcport': _auto, 364 'udp.dstport': _auto, 365 'udp.length': _auto, 366 'udp.port': _list(_dec), 367 'udp.checksum.status': _auto, 368 369 # IPv6 370 'ipv6.version': _auto, 371 'ipv6.src': _ipv6_addr, 372 'ipv6.src_host': _ipv6_addr, 373 'ipv6.dst': _ipv6_addr, 374 'ipv6.dst_host': _ipv6_addr, 375 'ipv6.addr': _list(_ipv6_addr), 376 'ipv6.tclass.dscp': _auto, 377 'ipv6.tclass.ecn': _auto, 378 'ipv6.flow': _auto, 379 'ipv6.hlim': _auto, 380 'ipv6.nxt': _auto, 381 'ipv6.hopopts.len': _auto, 382 'ipv6.hopopts.nxt': _auto, 383 'ipv6.hopopts.len_oct': _dec, 384 'ipv6.host': _list(_ipv6_addr), 385 'ipv6.plen': _auto, 386 'ipv6.opt.type.rest': _list(_auto), 387 'ipv6.opt.type.change': _list(_auto), 388 'ipv6.opt.type.action': _list(_auto), 389 'ipv6.opt.router_alert': _auto, 390 'ipv6.opt.padn': _str, 391 'ipv6.opt.length': _list(_auto), 392 'ipv6.opt.mpl.seed_id': _bytes, 393 'ipv6.opt.mpl.sequence': _auto, 394 'ipv6.opt.mpl.flag.v': _auto, 395 'ipv6.opt.mpl.flag.s': _auto, 396 'ipv6.opt.mpl.flag.rsv': _auto, 397 'ipv6.opt.mpl.flag.m': _auto, 398 399 # Eth 400 'eth.src': _eth_addr, 401 'eth.src_resolved': _eth_addr, 402 'eth.dst': _eth_addr, 403 'eth.dst_resolved': _eth_addr, 404 'eth.type': _auto, 405 'eth.addr': _list(_eth_addr), 406 'eth.addr_resolved': _list(_eth_addr), 407 'eth.ig': _list(_auto), 408 'eth.lg': _list(_auto), 409 # 6LOWPAN 410 '6lowpan.src': _ipv6_addr, 411 '6lowpan.dst': _ipv6_addr, 412 '6lowpan.udp.src': _auto, 413 '6lowpan.udp.dst': _auto, 414 '6lowpan.udp.checksum': _auto, 415 '6lowpan.frag.offset': _auto, 416 '6lowpan.frag.tag': _auto, 417 '6lowpan.frag.size': _auto, 418 '6lowpan.pattern': _list(_auto), 419 '6lowpan.hops': _auto, 420 '6lowpan.padding': _auto, 421 '6lowpan.next': _auto, 422 '6lowpan.flow': _auto, 423 '6lowpan.ecn': _auto, 424 '6lowpan.iphc.tf': _auto, 425 '6lowpan.iphc.m': _auto, 426 '6lowpan.iphc.nh': _auto, 427 '6lowpan.iphc.hlim': _auto, 428 '6lowpan.iphc.cid': _auto, 429 '6lowpan.iphc.sac': _auto, 430 '6lowpan.iphc.sam': _auto, 431 '6lowpan.iphc.dac': _auto, 432 '6lowpan.iphc.dam': _auto, 433 '6lowpan.iphc.sci': _auto, 434 '6lowpan.iphc.dci': _auto, 435 '6lowpan.iphc.sctx.prefix': _ipv6_addr, 436 '6lowpan.iphc.dctx.prefix': _ipv6_addr, 437 '6lowpan.mesh.v': _auto, 438 '6lowpan.nhc.pattern': _list(_auto), 439 '6lowpan.nhc.udp.checksum': _auto, 440 '6lowpan.nhc.udp.ports': _auto, 441 '6lowpan.nhc.ext.nh': _auto, 442 '6lowpan.nhc.ext.length': _auto, 443 '6lowpan.nhc.ext.eid': _auto, 444 '6lowpan.reassembled.length': _auto, 445 '6lowpan.fragments': _str, 446 '6lowpan.fragment.count': _auto, 447 '6lowpan.mesh.orig16': _auto, 448 '6lowpan.mesh.hops8': _auto, 449 '6lowpan.mesh.hops': _auto, 450 '6lowpan.mesh.f': _auto, 451 '6lowpan.mesh.dest16': _auto, 452 453 # ICMPv6 454 'icmpv6.type': _first(_auto), 455 'icmpv6.code': _first(_auto), 456 'icmpv6.checksum': _first(_auto), 457 'icmpv6.reserved': _raw_hex, 458 'icmpv6.resptime': _float, 459 'icmpv6.resp_to': _auto, 460 'icmpv6.mldr.nb_mcast_records': _auto, 461 'icmpv6.nd.ra.cur_hop_limit': _auto, 462 'icmpv6.nd.ns.target_address': _ipv6_addr, 463 'icmpv6.nd.na.target_address': _ipv6_addr, 464 'icmpv6.nd.na.flag.s': _auto, 465 'icmpv6.nd.na.flag.o': _auto, 466 'icmpv6.nd.na.flag.r': _auto, 467 'icmpv6.nd.na.flag.rsv': _auto, 468 'icmpv6.mldr.mar.record_type': _list(_auto), 469 'icmpv6.mldr.mar.aux_data_len': _list(_auto), 470 'icmpv6.mldr.mar.nb_sources': _list(_auto), 471 'icmpv6.mldr.mar.multicast_address': _list(_ipv6_addr), 472 'icmpv6.opt.type': _list(_auto), 473 'icmpv6.opt.nonce': _bytes, 474 'icmpv6.opt.linkaddr': _eth_addr, 475 'icmpv6.opt.src_linkaddr': _eth_addr, 476 'icmpv6.opt.target_linkaddr': _eth_addr, 477 'icmpv6.opt.route_lifetime': _auto, 478 'icmpv6.opt.route_info.flag.route_preference': _auto, 479 'icmpv6.opt.route_info.flag.reserved': _auto, 480 'icmpv6.opt.prefix.valid_lifetime': _auto, 481 'icmpv6.opt.prefix.preferred_lifetime': _auto, 482 'icmpv6.opt.prefix.length': _list(_auto), 483 'icmpv6.opt.prefix.flag.reserved': _auto, 484 'icmpv6.opt.prefix.flag.r': _auto, 485 'icmpv6.opt.prefix.flag.l': _auto, 486 'icmpv6.opt.prefix.flag.a': _auto, 487 'icmpv6.opt.length': _list(_auto), 488 'icmpv6.opt.reserved': _str, 489 'icmpv6.nd.ra.router_lifetime': _auto, 490 'icmpv6.nd.ra.retrans_timer': _auto, 491 'icmpv6.nd.ra.reachable_time': _auto, 492 'icmpv6.nd.ra.flag.rsv': _auto, 493 'icmpv6.nd.ra.flag.prf': _auto, 494 'icmpv6.nd.ra.flag.p': _auto, 495 'icmpv6.nd.ra.flag.o': _auto, 496 'icmpv6.nd.ra.flag.m': _auto, 497 'icmpv6.nd.ra.flag.h': _auto, 498 'icmpv6.echo.sequence_number': _auto, 499 'icmpv6.echo.identifier': _auto, 500 'icmpv6.data.len': _auto, 501 502 # COAP 503 'coap.code': _auto, 504 'coap.version': _auto, 505 'coap.type': _auto, 506 'coap.mid': _auto, 507 'coap.token_len': _auto, 508 'coap.token': _auto, 509 'coap.opt.uri_path': _list(_str), 510 'coap.opt.name': _list(_str), 511 'coap.opt.length': _list(_auto), 512 'coap.opt.uri_path_recon': _str, 513 'coap.payload': _payload, 514 'coap.payload_length': _auto, 515 'coap.payload_desc': _str, 516 'coap.opt.end_marker': _auto, 517 'coap.opt.desc': _list(_str), 518 'coap.opt.delta': _list(_auto), 519 'coap.response_to': _auto, 520 'coap.response_time': _float, 521 # COAP TLVS 522 'coap.tlv.type': _list(_auto), 523 'coap.tlv.status': _auto, 524 'coap.tlv.target_eid': _ipv6_addr, 525 'coap.tlv.ml_eid': _ext_addr, 526 'coap.tlv.last_transaction_time': _auto, 527 'coap.tlv.rloc16': _auto, 528 'coap.tlv.net_name': _str, 529 'coap.tlv.ext_mac_addr': _ext_addr, 530 'coap.tlv.router_mask_assigned': _auto, 531 'coap.tlv.router_mask_id_seq': _auto, 532 533 # dtls 534 'dtls.handshake.type': _list(_auto), 535 'dtls.handshake.cookie': _auto, 536 'dtls.record.content_type': _list(_auto), 537 'dtls.alert_message.desc': _auto, 538 539 # thread beacon 540 'thread_bcn.protocol': _auto, 541 'thread_bcn.version': _auto, 542 'thread_bcn.network_name': _str, 543 'thread_bcn.epid': _ext_addr, 544 545 # thread_address 546 'thread_address.tlv.len': _list(_auto), 547 'thread_address.tlv.type': _list(_auto), 548 'thread_address.tlv.status': _auto, 549 'thread_address.tlv.target_eid': _ipv6_addr, 550 'thread_address.tlv.ext_mac_addr': _ext_addr, 551 'thread_address.tlv.router_mask_id_seq': _auto, 552 'thread_address.tlv.router_mask_assigned': _bytes, 553 'thread_address.tlv.rloc16': _hex, 554 'thread_address.tlv.target_eid': _ipv6_addr, 555 'thread_address.tlv.ml_eid': _ext_addr, 556 557 # thread bl 558 'thread_bl.tlv.type': _list(_auto), 559 'thread_bl.tlv.len': _list(_auto), 560 'thread_bl.tlv.target_eid': _ipv6_addr, 561 'thread_bl.tlv.ml_eid': _ext_addr, 562 'thread_bl.tlv.last_transaction_time': _auto, 563 'thread_bl.tlv.timeout': _auto, 564 # THEAD NM 565 'thread_nm.tlv.type': _list(_auto), 566 'thread_nm.tlv.ml_eid': _ext_addr, 567 'thread_nm.tlv.target_eid': _ipv6_addr, 568 'thread_nm.tlv.status': _auto, 569 'thread_nm.tlv.timeout': _auto, 570 # thread_meshcop is not a real layer 571 'thread_meshcop.len_size_mismatch': _str, 572 'thread_meshcop.tlv.type': _list(_auto), 573 'thread_meshcop.tlv.len8': _list(_auto), 574 'thread_meshcop.tlv.net_name': _list(_str), # from thread_bl 575 'thread_meshcop.tlv.commissioner_id': _str, 576 'thread_meshcop.tlv.commissioner_sess_id': _auto, # from mle 577 "thread_meshcop.tlv.channel_page": _auto, # from ble 578 "thread_meshcop.tlv.channel": _list(_auto), # from ble 579 "thread_meshcop.tlv.chan_mask": _str, # from ble 580 'thread_meshcop.tlv.chan_mask_page': _auto, 581 'thread_meshcop.tlv.chan_mask_len': _auto, 582 'thread_meshcop.tlv.chan_mask_mask': _bytes, 583 'thread_meshcop.tlv.discovery_req_ver': _auto, 584 'thread_meshcop.tlv.discovery_rsp_ver': _auto, 585 'thread_meshcop.tlv.discovery_rsp_n': _auto, 586 'thread_meshcop.tlv.energy_list': _list(_auto), 587 'thread_meshcop.tlv.pan_id': _list(_auto), 588 'thread_meshcop.tlv.xpan_id': _bytes, 589 'thread_meshcop.tlv.ml_prefix': _bytes, 590 'thread_meshcop.tlv.master_key': _bytes, 591 'thread_meshcop.tlv.pskc': _bytes, 592 'thread_meshcop.tlv.sec_policy_rot': _auto, 593 'thread_meshcop.tlv.sec_policy_o': _auto, 594 'thread_meshcop.tlv.sec_policy_n': _auto, 595 'thread_meshcop.tlv.sec_policy_r': _auto, 596 'thread_meshcop.tlv.sec_policy_c': _auto, 597 'thread_meshcop.tlv.sec_policy_b': _auto, 598 'thread_meshcop.tlv.state': _auto, 599 'thread_meshcop.tlv.steering_data': _bytes, 600 'thread_meshcop.tlv.unknown': _bytes, 601 'thread_meshcop.tlv.udp_port': _list(_auto), 602 'thread_meshcop.tlv.ba_locator': _auto, 603 'thread_meshcop.tlv.jr_locator': _auto, 604 'thread_meshcop.tlv.active_tstamp': _auto, 605 'thread_meshcop.tlv.pending_tstamp': _auto, 606 'thread_meshcop.tlv.delay_timer': _auto, 607 'thread_meshcop.tlv.ipv6_addr': _list(_ipv6_addr), 608 609 # THREAD NWD 610 'thread_nwd.tlv.type': _list(_auto), 611 'thread_nwd.tlv.len': _list(_auto), 612 'thread_nwd.tlv.stable': _list(_auto), 613 'thread_nwd.tlv.service.t': _auto, 614 'thread_nwd.tlv.service.s_id': _auto, 615 'thread_nwd.tlv.service.s_data_len': _auto, 616 'thread_nwd.tlv.service.s_data.seqno': _auto, 617 'thread_nwd.tlv.service.s_data.rrdelay': _auto, 618 'thread_nwd.tlv.service.s_data.mlrtimeout': _auto, 619 'thread_nwd.tlv.server_16': _list(_auto), 620 'thread_nwd.tlv.border_router_16': _list(_auto), 621 'thread_nwd.tlv.sub_tlvs': _list(_str), 622 # TODO: support thread_nwd.tlv.prefix.length and thread_nwd.tlv.prefix.domain_id 623 'thread_nwd.tlv.prefix': _list(_ipv6_addr), 624 'thread_nwd.tlv.border_router.pref': _auto, 625 'thread_nwd.tlv.border_router.flag.s': _list(_auto), 626 'thread_nwd.tlv.border_router.flag.r': _list(_auto), 627 'thread_nwd.tlv.border_router.flag.p': _list(_auto), 628 'thread_nwd.tlv.border_router.flag.o': _list(_auto), 629 'thread_nwd.tlv.border_router.flag.n': _list(_auto), 630 'thread_nwd.tlv.border_router.flag.dp': _list(_auto), 631 'thread_nwd.tlv.border_router.flag.d': _list(_auto), 632 'thread_nwd.tlv.border_router.flag.c': _list(_auto), 633 'thread_nwd.tlv.6co.flag.reserved': _auto, 634 'thread_nwd.tlv.6co.flag.cid': _auto, 635 'thread_nwd.tlv.6co.flag.c': _list(_auto), 636 'thread_nwd.tlv.6co.context_length': _auto, 637 638 # Thread Diagnostic 639 'thread_diagnostic.tlv.type': _list(_auto), 640 'thread_diagnostic.tlv.len8': _list(_auto), 641 'thread_diagnostic.tlv.general': _list(_str) 642} 643 644_layer_containers = set() 645 646for key in _LAYER_FIELDS: 647 assert key.strip() == key and ' ' not in key, key 648 secs = key.split('.') 649 assert len(secs) >= 2 650 assert secs[0] in VALID_LAYER_NAMES, secs[0] 651 for i in range(len(secs) - 2): 652 path = secs[0] + '.' + '.'.join(secs[1:i + 2]) 653 assert path not in _LAYER_FIELDS, '%s can not be both field and path' % path 654 _layer_containers.add(path) 655 656 657def is_layer_field(uri: str) -> bool: 658 """ 659 Returns if the URI is a valid layer field. 660 661 :param uri: The layer field URI. 662 """ 663 return uri in _LAYER_FIELDS 664 665 666def is_layer_field_container(uri: str) -> bool: 667 """ 668 Returns if the URI is a valid layer field container. 669 670 :param uri: The layer field container URI. 671 """ 672 return uri in _layer_containers 673 674 675def get_layer_field(packet: RawPacket, field_uri: str) -> Any: 676 """ 677 Get a given layer field from the packet. 678 679 :param packet: The packet. 680 :param field_uri: The layer field URI. 681 682 :return: The specified layer field. 683 """ 684 assert isinstance(packet, RawPacket) 685 secs = field_uri.split('.') 686 layer_depth = 0 687 layer_name = secs[0] 688 if layer_name.endswith('inner'): 689 layer_name = layer_name[:-len('inner')] 690 field_uri = '.'.join([layer_name] + secs[1:]) 691 layer_depth = 1 692 693 if is_layer_field(field_uri): 694 candidate_layers = _get_candidate_layers(packet, layer_name) 695 for layers in candidate_layers: 696 if layer_depth >= len(layers): 697 continue 698 layer = layers[layer_depth] 699 v = layer.get_field(field_uri) 700 if v is not None: 701 try: 702 v = _LAYER_FIELDS[field_uri](v) 703 print("[%s = %r] " % (field_uri, v), file=sys.stderr) 704 return v 705 except Exception as ex: 706 raise ValueError('can not parse field %s = %r' % (field_uri, 707 (v.get_default_value(), v.raw_value))) from ex 708 709 print("[%s = %s] " % (field_uri, "null"), file=sys.stderr) 710 return nullField 711 712 elif is_layer_field_container(field_uri): 713 from pktverify.layer_fields_container import LayerFieldsContainer 714 return LayerFieldsContainer(packet, field_uri) 715 else: 716 raise NotImplementedError('Field %s is not valid, please add it to `_LAYER_FIELDS`' % field_uri) 717 718 719def check_layer_field_exists(packet, field_uri): 720 """ 721 Check if a given layer field URI exists in the packet. 722 723 :param packet: The packet to check. 724 :param field_uri: The layer field URI. 725 :return: Whether the layer field URI exists in the packet. 726 """ 727 assert isinstance(packet, RawPacket) 728 secs = field_uri.split('.') 729 layer_name = secs[0] 730 731 if not is_layer_field(field_uri) and not is_layer_field_container(field_uri): 732 raise NotImplementedError('%s is neither a field or field container' % field_uri) 733 734 candidate_layers = _get_candidate_layers(packet, layer_name) 735 for layers in candidate_layers: 736 for layer in layers: 737 for k, v in layer._all_fields.items(): 738 if k == field_uri or k.startswith(field_uri + '.'): 739 return True 740 741 return False 742 743 744def _get_candidate_layers(packet, layer_name): 745 if layer_name == 'thread_meshcop': 746 candidate_layer_names = ['thread_meshcop', 'mle', 'coap', 'thread_bl', 'thread_nm'] 747 elif layer_name == 'thread_nwd': 748 candidate_layer_names = ['mle', 'thread_address', 'thread_diagnostic'] 749 elif layer_name == 'wpan': 750 candidate_layer_names = ['wpan', 'mle'] 751 elif layer_name == 'ip': 752 candidate_layer_names = ['ip', 'ipv6'] 753 elif layer_name == 'thread_bcn': 754 candidate_layer_names = ['thread_bcn'] 755 else: 756 candidate_layer_names = [layer_name] 757 758 layers = [] 759 for ln in candidate_layer_names: 760 if hasattr(packet, ln): 761 layers.append(packet.get_multiple_layers(ln)) 762 763 return layers 764