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': _list(_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': _list(_ipv6_addr),
481    'icmpv6.opt.length': _list(_auto),
482    'icmpv6.opt.reserved': _str,
483    'icmpv6.nd.ra.router_lifetime': _auto,
484    'icmpv6.nd.ra.retrans_timer': _auto,
485    'icmpv6.nd.ra.reachable_time': _auto,
486    'icmpv6.nd.ra.flag.rsv': _auto,
487    'icmpv6.nd.ra.flag.prf': _auto,
488    'icmpv6.nd.ra.flag.p': _auto,
489    'icmpv6.nd.ra.flag.o': _auto,
490    'icmpv6.nd.ra.flag.m': _auto,
491    'icmpv6.nd.ra.flag.h': _auto,
492    'icmpv6.echo.sequence_number': _auto,
493    'icmpv6.echo.identifier': _auto,
494    'icmpv6.data.len': _auto,
495
496    # COAP
497    'coap.code': _auto,
498    'coap.version': _auto,
499    'coap.type': _auto,
500    'coap.mid': _auto,
501    'coap.token_len': _auto,
502    'coap.token': _auto,
503    'coap.opt.uri_path': _list(_str),
504    'coap.opt.name': _list(_str),
505    'coap.opt.length': _list(_auto),
506    'coap.opt.uri_path_recon': _str,
507    'coap.payload': _payload,
508    'coap.payload_length': _auto,
509    'coap.payload_desc': _str,
510    'coap.opt.end_marker': _auto,
511    'coap.opt.desc': _list(_str),
512    'coap.opt.delta': _list(_auto),
513    'coap.response_to': _auto,
514    'coap.response_time': _float,
515    # COAP TLVS
516    'coap.tlv.type': _list(_auto),
517    'coap.tlv.status': _auto,
518    'coap.tlv.target_eid': _ipv6_addr,
519    'coap.tlv.ml_eid': _ext_addr,
520    'coap.tlv.last_transaction_time': _auto,
521    'coap.tlv.rloc16': _auto,
522    'coap.tlv.net_name': _str,
523    'coap.tlv.ext_mac_addr': _ext_addr,
524    'coap.tlv.router_mask_assigned': _auto,
525    'coap.tlv.router_mask_id_seq': _auto,
526
527    # dtls
528    'dtls.handshake.type': _list(_auto),
529    'dtls.handshake.cookie': _auto,
530    'dtls.record.content_type': _list(_auto),
531    'dtls.alert_message.desc': _auto,
532
533    # thread beacon
534    'thread_bcn.protocol': _auto,
535    'thread_bcn.version': _auto,
536    'thread_bcn.network_name': _str,
537    'thread_bcn.epid': _ext_addr,
538
539    # thread_address
540    'thread_address.tlv.len': _list(_auto),
541    'thread_address.tlv.type': _list(_auto),
542    'thread_address.tlv.status': _auto,
543    'thread_address.tlv.target_eid': _ipv6_addr,
544    'thread_address.tlv.ext_mac_addr': _ext_addr,
545    'thread_address.tlv.router_mask_id_seq': _auto,
546    'thread_address.tlv.router_mask_assigned': _bytes,
547    'thread_address.tlv.rloc16': _hex,
548    'thread_address.tlv.target_eid': _ipv6_addr,
549    'thread_address.tlv.ml_eid': _ext_addr,
550
551    # thread bl
552    'thread_bl.tlv.type': _list(_auto),
553    'thread_bl.tlv.len': _list(_auto),
554    'thread_bl.tlv.target_eid': _ipv6_addr,
555    'thread_bl.tlv.ml_eid': _ext_addr,
556    'thread_bl.tlv.last_transaction_time': _auto,
557    'thread_bl.tlv.timeout': _auto,
558    # THEAD NM
559    'thread_nm.tlv.type': _list(_auto),
560    'thread_nm.tlv.ml_eid': _ext_addr,
561    'thread_nm.tlv.target_eid': _ipv6_addr,
562    'thread_nm.tlv.status': _auto,
563    'thread_nm.tlv.timeout': _auto,
564    # thread_meshcop is not a real layer
565    'thread_meshcop.len_size_mismatch': _str,
566    'thread_meshcop.tlv.type': _list(_auto),
567    'thread_meshcop.tlv.len8': _list(_auto),
568    'thread_meshcop.tlv.net_name': _list(_str),  # from thread_bl
569    'thread_meshcop.tlv.commissioner_id': _str,
570    'thread_meshcop.tlv.commissioner_sess_id': _auto,  # from mle
571    "thread_meshcop.tlv.channel_page": _auto,  # from ble
572    "thread_meshcop.tlv.channel": _list(_auto),  # from ble
573    "thread_meshcop.tlv.chan_mask": _str,  # from ble
574    'thread_meshcop.tlv.chan_mask_page': _auto,
575    'thread_meshcop.tlv.chan_mask_len': _auto,
576    'thread_meshcop.tlv.chan_mask_mask': _bytes,
577    'thread_meshcop.tlv.discovery_req_ver': _auto,
578    'thread_meshcop.tlv.discovery_rsp_ver': _auto,
579    'thread_meshcop.tlv.discovery_rsp_n': _auto,
580    'thread_meshcop.tlv.energy_list': _list(_auto),
581    'thread_meshcop.tlv.pan_id': _list(_auto),
582    'thread_meshcop.tlv.xpan_id': _bytes,
583    'thread_meshcop.tlv.ml_prefix': _bytes,
584    'thread_meshcop.tlv.master_key': _bytes,
585    'thread_meshcop.tlv.pskc': _bytes,
586    'thread_meshcop.tlv.sec_policy_rot': _auto,
587    'thread_meshcop.tlv.sec_policy_o': _auto,
588    'thread_meshcop.tlv.sec_policy_n': _auto,
589    'thread_meshcop.tlv.sec_policy_r': _auto,
590    'thread_meshcop.tlv.sec_policy_c': _auto,
591    'thread_meshcop.tlv.sec_policy_b': _auto,
592    'thread_meshcop.tlv.state': _auto,
593    'thread_meshcop.tlv.steering_data': _bytes,
594    'thread_meshcop.tlv.unknown': _bytes,
595    'thread_meshcop.tlv.udp_port': _list(_auto),
596    'thread_meshcop.tlv.ba_locator': _auto,
597    'thread_meshcop.tlv.jr_locator': _auto,
598    'thread_meshcop.tlv.active_tstamp': _auto,
599    'thread_meshcop.tlv.pending_tstamp': _auto,
600    'thread_meshcop.tlv.delay_timer': _auto,
601    'thread_meshcop.tlv.ipv6_addr': _list(_ipv6_addr),
602
603    # THREAD NWD
604    'thread_nwd.tlv.type': _list(_auto),
605    'thread_nwd.tlv.len': _list(_auto),
606    'thread_nwd.tlv.stable': _list(_auto),
607    'thread_nwd.tlv.service.t': _auto,
608    'thread_nwd.tlv.service.s_id': _auto,
609    'thread_nwd.tlv.service.s_data_len': _auto,
610    'thread_nwd.tlv.service.s_data.seqno': _auto,
611    'thread_nwd.tlv.service.s_data.rrdelay': _auto,
612    'thread_nwd.tlv.service.s_data.mlrtimeout': _auto,
613    'thread_nwd.tlv.server_16': _list(_auto),
614    'thread_nwd.tlv.border_router_16': _list(_auto),
615    'thread_nwd.tlv.sub_tlvs': _list(_str),
616    # TODO: support thread_nwd.tlv.prefix.length and thread_nwd.tlv.prefix.domain_id
617    'thread_nwd.tlv.prefix': _list(_ipv6_addr),
618    'thread_nwd.tlv.border_router.pref': _auto,
619    'thread_nwd.tlv.border_router.flag.s': _list(_auto),
620    'thread_nwd.tlv.border_router.flag.r': _list(_auto),
621    'thread_nwd.tlv.border_router.flag.p': _list(_auto),
622    'thread_nwd.tlv.border_router.flag.o': _list(_auto),
623    'thread_nwd.tlv.border_router.flag.n': _list(_auto),
624    'thread_nwd.tlv.border_router.flag.dp': _list(_auto),
625    'thread_nwd.tlv.border_router.flag.d': _list(_auto),
626    'thread_nwd.tlv.border_router.flag.c': _list(_auto),
627    'thread_nwd.tlv.6co.flag.reserved': _auto,
628    'thread_nwd.tlv.6co.flag.cid': _auto,
629    'thread_nwd.tlv.6co.flag.c': _list(_auto),
630    'thread_nwd.tlv.6co.context_length': _auto,
631
632    # Thread Diagnostic
633    'thread_diagnostic.tlv.type': _list(_auto),
634    'thread_diagnostic.tlv.len8': _list(_auto),
635    'thread_diagnostic.tlv.general': _list(_str),
636
637    # DNS
638    'dns.resp.ttl': _auto,
639    'dns.flags.response': _auto,
640}
641
642_layer_containers = set()
643
644for key in _LAYER_FIELDS:
645    assert key.strip() == key and ' ' not in key, key
646    secs = key.split('.')
647    assert len(secs) >= 2
648    assert secs[0] in VALID_LAYER_NAMES, secs[0]
649    for i in range(len(secs) - 2):
650        path = secs[0] + '.' + '.'.join(secs[1:i + 2])
651        assert path not in _LAYER_FIELDS, '%s can not be both field and path' % path
652        _layer_containers.add(path)
653
654
655def is_layer_field(uri: str) -> bool:
656    """
657    Returns if the URI is a valid layer field.
658
659    :param uri: The layer field URI.
660    """
661    return uri in _LAYER_FIELDS
662
663
664def is_layer_field_container(uri: str) -> bool:
665    """
666    Returns if the URI is a valid layer field container.
667
668    :param uri: The layer field container URI.
669    """
670    return uri in _layer_containers
671
672
673def get_layer_field(packet: RawPacket, field_uri: str) -> Any:
674    """
675    Get a given layer field from the packet.
676
677    :param packet: The packet.
678    :param field_uri: The layer field URI.
679
680    :return: The specified layer field.
681    """
682    assert isinstance(packet, RawPacket)
683    secs = field_uri.split('.')
684    layer_depth = 0
685    layer_name = secs[0]
686    if layer_name.endswith('inner'):
687        layer_name = layer_name[:-len('inner')]
688        field_uri = '.'.join([layer_name] + secs[1:])
689        layer_depth = 1
690
691    if is_layer_field(field_uri):
692        candidate_layers = _get_candidate_layers(packet, layer_name)
693        for layers in candidate_layers:
694            if layer_depth >= len(layers):
695                continue
696            layer = layers[layer_depth]
697            v = layer.get_field(field_uri)
698            if v is not None:
699                try:
700                    v = _LAYER_FIELDS[field_uri](v)
701                    print("[%s = %r] " % (field_uri, v), file=sys.stderr)
702                    return v
703                except Exception as ex:
704                    raise ValueError('can not parse field %s = %r' % (field_uri,
705                                                                      (v.get_default_value(), v.raw_value))) from ex
706
707        print("[%s = %s] " % (field_uri, "null"), file=sys.stderr)
708        return nullField
709
710    elif is_layer_field_container(field_uri):
711        from pktverify.layer_fields_container import LayerFieldsContainer
712        return LayerFieldsContainer(packet, field_uri)
713    else:
714        raise NotImplementedError('Field %s is not valid, please add it to `_LAYER_FIELDS`' % field_uri)
715
716
717def check_layer_field_exists(packet, field_uri):
718    """
719    Check if a given layer field URI exists in the packet.
720
721    :param packet: The packet to check.
722    :param field_uri: The layer field URI.
723    :return: Whether the layer field URI exists in the packet.
724    """
725    assert isinstance(packet, RawPacket)
726    secs = field_uri.split('.')
727    layer_name = secs[0]
728
729    if not is_layer_field(field_uri) and not is_layer_field_container(field_uri):
730        raise NotImplementedError('%s is neither a field or field container' % field_uri)
731
732    candidate_layers = _get_candidate_layers(packet, layer_name)
733    for layers in candidate_layers:
734        for layer in layers:
735            for k, v in layer._all_fields.items():
736                if k == field_uri or k.startswith(field_uri + '.'):
737                    return True
738
739    return False
740
741
742def _get_candidate_layers(packet, layer_name):
743    if layer_name == 'thread_meshcop':
744        candidate_layer_names = ['thread_meshcop', 'mle', 'coap', 'thread_bl', 'thread_nm']
745    elif layer_name == 'thread_nwd':
746        candidate_layer_names = ['mle', 'thread_address', 'thread_diagnostic']
747    elif layer_name == 'wpan':
748        candidate_layer_names = ['wpan', 'mle']
749    elif layer_name == 'ip':
750        candidate_layer_names = ['ip', 'ipv6']
751    elif layer_name == 'thread_bcn':
752        candidate_layer_names = ['thread_bcn']
753    else:
754        candidate_layer_names = [layer_name]
755
756    layers = []
757    for ln in candidate_layer_names:
758        if hasattr(packet, ln):
759            layers.append(packet.get_multiple_layers(ln))
760
761    return layers
762