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#
29
30import unittest
31
32from config import ADDRESS_TYPE
33from pktverify import consts
34
35import config
36import thread_cert
37
38LEADER = 1
39SED_1 = 2
40SSED_1 = 3
41
42POLL_PERIOD = 3000  # 3s
43
44
45class LowPower_7_1_01(thread_cert.TestCase):
46    USE_MESSAGE_FACTORY = False
47    TOPOLOGY = {
48        LEADER: {
49            'version': '1.2',
50            'name': 'LEADER',
51            'mode': 'rdn',
52            'allowlist': [SED_1, SSED_1],
53        },
54        SED_1: {
55            'version': '1.2',
56            'name': 'SED_1',
57            'mode': '-',
58            'allowlist': [LEADER],
59        },
60        SSED_1: {
61            'version': '1.2',
62            'name': 'SSED_1',
63            'mode': '-',
64            'allowlist': [LEADER],
65        }
66    }
67    """All nodes are created with default configurations"""
68
69    def test(self):
70        self.nodes[LEADER].start()
71        self.simulator.go(config.LEADER_STARTUP_DELAY)
72        self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
73
74        self.nodes[SED_1].set_pollperiod(POLL_PERIOD)
75        self.nodes[SED_1].start()
76        self.simulator.go(5)
77        self.assertEqual(self.nodes[SED_1].get_state(), 'child')
78
79        self.nodes[SSED_1].set_csl_period(consts.CSL_DEFAULT_PERIOD)
80        self.nodes[SSED_1].start()
81        self.simulator.go(5)
82        self.assertEqual(self.nodes[SSED_1].get_state(), 'child')
83
84        leader_addr = self.nodes[LEADER].get_ip6_address(ADDRESS_TYPE.LINK_LOCAL)
85
86        # Step 3 - Verify connectivity by instructing each device to send an ICMPv6 Echo Request to the DUT
87        self.assertTrue(self.nodes[SED_1].ping(leader_addr, timeout=POLL_PERIOD * 2 / 1000))
88        self.assertTrue(self.nodes[SSED_1].ping(leader_addr))
89        self.simulator.go(5)
90
91        # Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
92        # Request to the DUT
93        # MLE Link Metrics Management TLV Payload:
94        # - Enhanced ACK Configuration Sub-TLV
95        # -- Enh-ACK Flags = 1 (register a configuration)
96        # -- Concatenation of Link Metric Type ID Flags = 0x00:
97        # --- Item1: (0)(0)(001)(010) = 0x0a
98        # ---- E = 0
99        # ---- L = 0
100        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
101        # ---- Metrics Enum = 2 (Link Margin)
102        self.nodes[SED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'm', mode='async')
103        self.simulator.go(5)
104
105        # Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
106        # Request to the DUT
107        # MLE Link Metrics Management TLV Payload:
108        # - Enhanced ACK Configuration Sub-TLV
109        # -- Enh-ACK Flags = 1 (register a configuration)
110        # -- Concatenation of Link Metric Type ID Flags = 0x00:
111        # --- Item1: (0)(0)(001)(010) = 0x0a
112        # --- Item2: (0)(0)(001)(011) = 0x0b
113        # ---- E = 0
114        # ---- L = 0
115        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
116        # ---- Metrics Enum = 2 (Link Margin)
117        # ---- Metrics Enum = 3 (RSSI)
118        self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'mr', mode='async')
119        self.simulator.go(5)
120
121        # Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
122        # message to 0b10
123        self.nodes[SSED_1].send_mac_emptydata()
124        self.simulator.go(5)
125
126        # Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
127        # message # to 0b10
128        self.nodes[SED_1].send_mac_emptydata()
129        self.simulator.go(5)
130
131        # Step 12 - SSED_1 clears its Enhanced ACK link metrics configuration by # sending a Link Metrics Management
132        # Request to the DUT
133        # Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
134        self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, False, '', mode='async')
135        self.simulator.go(5)
136
137        # Step 14 - SSED_1 Sends a MLE Data Message with setting Frame Version subfield within the MAC header of the
138        # message to 0b10
139        self.nodes[SSED_1].send_mac_emptydata()
140        self.simulator.go(5)
141
142        # Step 16 - This step verifies that Enhanced ACKs cannot be enabled while requesting 3 metric types by
143        # instructing the device to send the following Link Metrics Management Request to the DUT
144        # MLE Link Metrics Management TLV Payload:
145        # - Enhanced ACK Configuration Sub-TLV
146        # -- Enh-ACK Flags = 1 (register a configuration)
147        # -- Concatenation of Link Metric Type ID Flags = 0x00:
148        # --- Item1: (0)(0)(001)(001) = 0x09
149        # --- Item2: (0)(0)(001)(010) = 0x0a
150        # --- Item3: (0)(0)(001)(011) = 0x0b
151        # ---- E = 0
152        # ---- L = 0
153        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
154        # ---- Metrics Enum = 1 (Layer 2 LQI)
155        # ---- Metrics Enum = 2 (Link Margin)
156        # ---- Metrics Enum = 3 (RSSI)
157        self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr, True, 'qmr', mode='async')
158        self.simulator.go(5)
159
160        # Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
161        # enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
162        # MLE Link Metrics Management TLV Payload:
163        # - Enhanced ACK Configuration Sub-TLV
164        # -- Enh-ACK Flags = 1 (register a configuration)
165        # -- Concatenation of Link Metric Type ID Flags = 0x00:
166        # --- Item1: (0)(0)(010)(010) = 0x12
167        # ---- E = 0
168        # ---- L = 0
169        # ---- Type/Average Enum = 2 (Reserved)
170        # ---- Metrics Enum = 2 (Link Margin)
171        self.nodes[SSED_1].link_metrics_config_req_enhanced_ack_based_probing(leader_addr,
172                                                                              True,
173                                                                              'm',
174                                                                              'r',
175                                                                              mode='async')
176        self.simulator.go(5)
177
178    def verify(self, pv):
179        pkts = pv.pkts
180        pv.summary.show()
181        LEADER = pv.vars['LEADER']
182        SED_1 = pv.vars['SED_1']
183        SSED_1 = pv.vars['SSED_1']
184
185        # Step 3 - The DUT MUST send ICMPv6 Echo Responses to both SED1 & SSED1
186        pkts.filter_wpan_src64(LEADER) \
187            .filter_wpan_dst64(SED_1) \
188            .filter_ping_reply() \
189            .must_next()
190        pkts.filter_wpan_src64(LEADER) \
191            .filter_wpan_dst64(SSED_1) \
192            .filter_ping_reply() \
193            .must_next()
194
195        # Step 4 - SED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
196        # Request to the DUT
197        # MLE Link Metrics Management TLV Payload:
198        # - Enhanced ACK Configuration Sub-TLV
199        # -- Enh-ACK Flags = 1 (register a configuration)
200        # -- Concatenation of Link Metric Type ID Flags = 0x00:
201        # --- Item1: (0)(0)(001)(010) = 0x0a
202        # ---- E = 0
203        # ---- L = 0
204        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
205        # ---- Metrics Enum = 2 (Link Margin)
206        pkts.filter_wpan_src64(SED_1) \
207            .filter_wpan_dst64(LEADER) \
208            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
209            .filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
210            .filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
211            .filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a') \
212            .must_next()
213
214        # Step 5 - The DUT MUST send a Link Metrics Management Response to SED_1 containing the following TLVs:
215        # - MLE LInk Metrics Management TLV
216        # -- Link Metrics Status Sub-TLV = 0 (Success)
217        pkts.filter_wpan_src64(LEADER) \
218            .filter_wpan_dst64(SED_1) \
219            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
220            .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
221            .must_next()
222
223        # Step 6 - SSED_1 enables IEEE 802.15.4-2015 Enhanced ACK based Probing by sending a Link Metrics Management
224        # Request to the DUT
225        # MLE Link Metrics Management TLV Payload:
226        # - Enhanced ACK Configuration Sub-TLV
227        # -- Enh-ACK Flags = 1 (register a configuration)
228        # -- Concatenation of Link Metric Type ID Flags = 0x00:
229        # --- Item1: (0)(0)(001)(010) = 0x0a
230        # --- Item2: (0)(0)(001)(011) = 0x0b
231        # ---- E = 0
232        # ---- L = 0
233        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
234        # ---- Metrics Enum = 2 (Link Margin)
235        # ---- Metrics Enum = 3 (RSSI)
236        pkts.filter_wpan_src64(SSED_1) \
237            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
238            .filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
239            .filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
240            .filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '0a0b') \
241            .must_next()
242
243        # Step 7 - The DUT MUST send a Link Metrics Management Response to SSED_1
244        pkts.filter_wpan_src64(LEADER) \
245            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
246            .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
247            .must_next()
248
249        # Step 8 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
250        # message to 0b10
251        pkt = pkts.filter_wpan_src64(SSED_1) \
252            .filter_wpan_data() \
253            .filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
254            .must_next()
255        ack_seq_no = pkt.wpan.seq_no
256
257        # Step 9 - The DUT MUST reply to SSED_1 with an Enhanced ACK containing the following:
258        # - Frame Control Field
259        # -- Security Enabled = True
260        # - Header IE
261        # -- Element ID = 0x00
262        # --- Vendor CID = 0xEAB89B  (Thread Group)
263        # --- Vendor Specific Information
264        # ---- 1st byte = 0 (Enhanced ACK Link Metrics)
265        # ---- 2nd byte ... Link Margin data
266        # ---- 3rd byte ... RSSI data
267        pkts.filter_wpan_ack() \
268            .filter_wpan_seq(ack_seq_no) \
269            .filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
270            .must_next()
271
272        # Step 10 - SED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
273        # message to 0b10
274        pkt = pkts.filter_wpan_src64(SED_1) \
275            .filter_wpan_data() \
276            .filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
277            .must_next()
278        ack_seq_no = pkt.wpan.seq_no
279
280        # Step 11 - The DUT MUST reply to SED_1 with an Enhanced ACK containing the following:
281        # - Frame Control Field
282        # -- Security Enabled = True
283        # - Header IE
284        # -- Element ID = 0x00
285        # --- Vendor CID = 0xEAB89B  (Thread Group)
286        # --- Vendor Specific Information
287        # ---- 1st byte = 0 (Enhanced ACK Link Metrics)
288        # ---- 2nd byte ... Link Margin data
289        pkts.filter_wpan_ack() \
290            .filter_wpan_seq(ack_seq_no) \
291            .filter(lambda p: p.wpan.payload_ie.vendor.oui == consts.THREAD_IEEE_802154_COMPANY_ID) \
292            .must_next()
293
294        # Step 12 - SSED_1 clears enhanced ACK link metrics configuration by instructing it to send a Link Metrics
295        # Management Request to the DUT
296        # - MLE Link Metrics Management TLV Payload
297        # -- Enhanced ACK Configuration Sub-TLV
298        # -- Enh-ACK Flags = 0 (clear enhanced ACK link metric config)
299        pkts.filter_wpan_src64(SSED_1) \
300            .filter_wpan_dst64(LEADER) \
301            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
302            .filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
303            .filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_CLEAR) \
304            .must_next()
305
306        # Step 13 - The DUT MUST send Link Metrics Management Response to SSED_1 containing the following:
307        # - MLE Link Metrics Management TLV
308        # -- Link Metrics Status Sub-TLV = 0 (Success)
309        pkts.filter_wpan_src64(LEADER) \
310            .filter_wpan_dst64(SSED_1) \
311            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
312            .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_SUCCESS) \
313            .must_next()
314
315        # Step 14 - SSED_1 sends an MLE Data Message with setting Frame Version subfield within the MAC header of the
316        # message to 0b10
317        pkt = pkts.filter_wpan_src64(SSED_1) \
318            .filter_wpan_data() \
319            .filter_wpan_version(consts.MAC_FRAME_VERSION_2015) \
320            .must_next()
321        ack_seq_no = pkt.wpan.seq_no
322
323        # Step 15 - The DUT MUST NOT include a Link Metrics Report in the ACK
324        pkts.filter_wpan_ack() \
325            .filter_wpan_seq(ack_seq_no) \
326            .filter_wpan_ie_not_present() \
327            .must_next()
328
329        # Step 16 - This step verifies that Enhanced ACKS cannot be enabled while requesting 3 metric types by
330        # instructing the device to send the following Link Metrics Management Request to the DUT:
331        # MLE Link Metrics Management TLV Payload:
332        # - Enhanced ACK Configuration Sub-TLV
333        # -- Enh-ACK Flags = 1 (register a configuration)
334        # -- Concatenation of Link Metric Type ID Flags = 0x00:
335        # --- Item1: (0)(0)(001)(001) = 0x09
336        # --- Item2: (0)(0)(001)(010) = 0x0a
337        # --- Item3: (0)(0)(001)(011) = 0x0b
338        # ---- E = 0
339        # ---- L = 0
340        # ---- Type/Average Enum = 1 (Exponential Moving Avg)
341        # ---- Metrics Enum = 1 (Layer 2 LQI)
342        # ---- Metrics Enum = 2 (Link Margin)
343        # ---- Metrics Enum = 3 (RSSI)
344        pkts.filter_wpan_src64(SSED_1) \
345            .filter_wpan_dst64(LEADER) \
346            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
347            .filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
348            .filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
349            .filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '090a0b') \
350            .must_next()
351
352        # Step 17 - Leader automatically responds to the invalid query from SSED_1 with a failure
353        # The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
354        # - MLE Link Metrics Management TLV
355        # -- Link Metrics Status Sub-TLV = 254 (Failure)
356        pkts.filter_wpan_src64(LEADER) \
357            .filter_wpan_dst64(SSED_1) \
358            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
359            .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_OTHER_ERROR) \
360            .must_next()
361
362        # Step 18 - This step verifies that Enhanced ACKs cannot be enabled while requesting a reserved Type/Average
363        # enum of value 2 by instructing the device to send the following Link Metrics Management Request to the DUT
364        # MLE Link Metrics Management TLV Payload:
365        # - Enhanced ACK Configuration Sub-TLV
366        # -- Enh-ACK Flags = 1 (register a configuration)
367        # -- Concatenation of Link Metric Type ID Flags = 0x00:
368        # --- Item1: (0)(0)(010)(010) = 0x12
369        # ---- E = 0
370        # ---- L = 0
371        # ---- Type/Average Enum = 2 (Reserved)
372        # ---- Metrics Enum = 2 (Link Margin)
373        pkts.filter_wpan_src64(SSED_1) \
374            .filter_wpan_dst64(LEADER) \
375            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_REQUEST) \
376            .filter(lambda p: consts.LM_ENHANCED_ACK_CONFIGURATION_SUB_TLV in p.mle.tlv.link_sub_tlv) \
377            .filter(lambda p: p.mle.tlv.link_enh_ack_flags == consts.LINK_METRICS_ENH_ACK_PROBING_REGISTER) \
378            .filter(lambda p: p.mle.tlv.link_requested_type_id_flags == '12') \
379            .must_next()
380
381        # Step 19 - Leader automatically responds to the invalid query from SSED_1 with a failure
382        # The DUT MUST send Link Metrics Management Response to SSED_1containing the following:
383        # - MLE Link Metrics Management TLV
384        # -- Link Metrics Status Sub-TLV = 254 (Failure)
385        pkts.filter_wpan_src64(LEADER) \
386            .filter_wpan_dst64(SSED_1) \
387            .filter_mle_cmd(consts.MLE_LINK_METRICS_MANAGEMENT_RESPONSE) \
388            .filter(lambda p: p.mle.tlv.link_status_sub_tlv == consts.LINK_METRICS_STATUS_OTHER_ERROR) \
389            .must_next()
390
391
392if __name__ == '__main__':
393    unittest.main()
394