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
31import copy
32
33import config
34import thread_cert
35from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE, MLE_CHILD_ID_RESPONSE, SVR_DATA_URI, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
36from pktverify.packet_verifier import PacketVerifier
37from pktverify.bytes import Bytes
38from pktverify.addrs import Ipv6Addr
39from pktverify.null_field import nullField
40
41LEADER = 1
42ROUTER_1 = 2
43ROUTER_2 = 3
44MED = 4
45SED = 5
46
47MTDS = [MED, SED]
48PREFIX_2001 = '2001:0db8:0001::/64'
49
50# Test Purpose and Description:
51# -----------------------------
52# The purpose of this test case is to verify that network data is properly updated
53# when a server from the network leaves and rejoins.
54# Router_1 is configured as Border Router for prefix 2001:db8:1::/64.
55# Router_2 is configured as Border Router for prefix 2001:db8:1::/64.
56# MED is configured to require complete network data.
57# SED is configured to request only stable network data.
58#
59# Test Topology:
60# -------------
61#             SED
62#              |
63# Router_1 - Leader(DUT) - MED
64#              |
65#            Router_2
66#
67# DUT Types:
68# ----------
69# Leader
70
71
72class Cert_7_1_6_BorderRouterAsLeader(thread_cert.TestCase):
73    USE_MESSAGE_FACTORY = False
74
75    TOPOLOGY = {
76        LEADER: {
77            'name': 'LEADER',
78            'mode': 'rdn',
79            'allowlist': [ROUTER_1, ROUTER_2, MED, SED]
80        },
81        ROUTER_1: {
82            'name': 'ROUTER_1',
83            'mode': 'rdn',
84            'allowlist': [LEADER]
85        },
86        ROUTER_2: {
87            'name': 'ROUTER_2',
88            'mode': 'rdn',
89            'allowlist': [LEADER]
90        },
91        MED: {
92            'name': 'MED',
93            'is_mtd': True,
94            'mode': 'rn',
95            'allowlist': [LEADER]
96        },
97        SED: {
98            'name': 'SED',
99            'is_mtd': True,
100            'mode': '-',
101            'timeout': config.DEFAULT_CHILD_TIMEOUT,
102            'allowlist': [LEADER]
103        },
104    }
105    # override wireshark preferences with case needed parameters
106    CASE_WIRESHARK_PREFS = WIRESHARK_OVERRIDE_PREFS
107    CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
108
109    def _setUpRouter_1(self):
110        self.nodes[ROUTER_1].add_allowlist(self.nodes[LEADER].get_addr64())
111        self.nodes[ROUTER_1].enable_allowlist()
112        self.nodes[ROUTER_1].set_router_selection_jitter(1)
113
114    def test(self):
115        self.nodes[LEADER].start()
116        self.simulator.go(config.LEADER_STARTUP_DELAY)
117        self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
118
119        for i in (2, 3):
120            self.nodes[i].start()
121            self.simulator.go(config.ROUTER_STARTUP_DELAY)
122            self.assertEqual(self.nodes[i].get_state(), 'router')
123
124        self.nodes[MED].start()
125        self.simulator.go(5)
126        self.assertEqual(self.nodes[MED].get_state(), 'child')
127
128        self.nodes[SED].start()
129        self.simulator.go(5)
130        self.assertEqual(self.nodes[SED].get_state(), 'child')
131
132        self.collect_rlocs()
133
134        self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros')
135        self.nodes[ROUTER_1].register_netdata()
136        self.nodes[ROUTER_2].add_prefix(PREFIX_2001, 'paro')
137        self.nodes[ROUTER_2].register_netdata()
138        self.simulator.go(10)
139        self.collect_ipaddrs()
140
141        self.nodes[ROUTER_1].reset()
142        self._setUpRouter_1()
143        self.simulator.go(720)
144
145        self.nodes[ROUTER_1].start()
146        self.simulator.go(config.ROUTER_RESET_DELAY)
147        self.assertEqual(self.nodes[ROUTER_1].get_state(), 'router')
148        self.collect_rloc16s()
149
150        self.nodes[ROUTER_1].add_prefix(PREFIX_2001, 'paros')
151        self.nodes[ROUTER_1].register_netdata()
152        self.simulator.go(10)
153
154        dut_addr = self.nodes[LEADER].get_addr(PREFIX_2001)
155        self.assertTrue(self.nodes[ROUTER_1].ping(dut_addr))
156        self.simulator.go(1)
157        self.assertTrue(self.nodes[SED].ping(dut_addr))
158
159    def verify(self, pv):
160        pkts = pv.pkts
161        pv.summary.show()
162
163        LEADER = pv.vars['LEADER']
164        LEADER_RLOC = pv.vars['LEADER_RLOC']
165        LEADER_RLOC16 = pv.vars['LEADER_RLOC16']
166        ROUTER_1 = pv.vars['ROUTER_1']
167        ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16']
168        ROUTER_1_RLOC = pv.vars['ROUTER_1_RLOC']
169        ROUTER_2 = pv.vars['ROUTER_2']
170        ROUTER_2_RLOC16 = pv.vars['ROUTER_2_RLOC16']
171        SED = pv.vars['SED']
172        MED = pv.vars['MED']
173        GUA = {}
174
175        for node in ('LEADER', 'ROUTER_1', 'SED'):
176            for addr in pv.vars['%s_IPADDRS' % node]:
177                if addr.startswith(Bytes(PREFIX_2001[:-5])):
178                    GUA[node] = addr
179
180        # Step 1: Ensure topology is formed correctly
181        pv.verify_attached('ROUTER_1', 'LEADER')
182        pv.verify_attached('ROUTER_2', 'LEADER')
183        pv.verify_attached('MED', 'LEADER', 'MTD')
184        pv.verify_attached('SED', 'LEADER', 'MTD')
185        _pkt = pkts.last()
186
187        # Step 2,3: Router_1 and Router_2  MUST send a CoAP Server Data
188        #           Notification frame to the Leader including the server’s
189        #           information(Prefix, Border Router):
190        #             CoAP Request URI
191        #                 coap://[<Leader address>]:MM/a/sd
192        #             CoAP Payload
193        #                 Thread Network Data TLV
194
195        # Step 4: Leader sends a CoAP ACK frame to each of Router_1 and
196        #         Router_2
197        for i in (1, 2):
198            with pkts.save_index():
199                pkts.filter_wpan_src64(pv.vars['ROUTER_%d' %i]).\
200                    filter_wpan_dst16(LEADER_RLOC16).\
201                    filter_coap_request(SVR_DATA_URI).\
202                    filter(lambda p:
203                           [Ipv6Addr(PREFIX_2001[:-3])] ==
204                           p.thread_nwd.tlv.prefix and\
205                           [pv.vars['ROUTER_%d_RLOC16' %i]] ==
206                           p.thread_nwd.tlv.border_router_16
207                           ).\
208                    must_next()
209                pkts.filter_wpan_src64(LEADER).\
210                    filter_ipv6_dst(pv.vars['ROUTER_%d_RLOC' %i]).\
211                    filter_coap_ack(SVR_DATA_URI).\
212                    must_next()
213
214        # Step 5: Leader MUST multicast MLE Data Response with the new
215        #         information collected from Router_1 and Router_2,
216        #         including the following TLVs:,
217        #              - Source Address TLV
218        #              - Leader Data TLV
219        #                  - Data Version field <incremented>
220        #                  - Stable Data Version field <incremented>
221        #              - Network Data TLV
222        #                  - At least one Prefix TLV (Prefix 1)
223        #                      - Two Border Router sub-TLVs
224        #                      - 6LoWPAN ID sub-TLV
225        _dr_pkt = pkts.filter_wpan_src64(LEADER).\
226            filter_LLANMA().\
227            filter_mle_cmd(MLE_DATA_RESPONSE).\
228            filter(lambda p: {
229                              NETWORK_DATA_TLV,
230                              SOURCE_ADDRESS_TLV,
231                              LEADER_DATA_TLV
232                             } <= set(p.mle.tlv.type) and\
233                   p.thread_nwd.tlv.border_router.flag.p == [1] and\
234                   p.thread_nwd.tlv.border_router.flag.s == [1] and\
235                   p.thread_nwd.tlv.border_router.flag.r == [1] and\
236                   p.thread_nwd.tlv.border_router.flag.o == [1] and\
237                   [Ipv6Addr(PREFIX_2001[:-3])] ==
238                   p.thread_nwd.tlv.prefix
239                   ).\
240            must_next()
241        with pkts.save_index():
242            _dr_pkt1 = pkts.filter_wpan_src64(LEADER).\
243                filter_LLANMA().\
244                filter_mle_cmd(MLE_DATA_RESPONSE).\
245                filter(lambda p: {
246                                  NETWORK_DATA_TLV,
247                                  SOURCE_ADDRESS_TLV,
248                                  LEADER_DATA_TLV
249                                 } <= set(p.mle.tlv.type) and\
250                                 {
251                                  NWD_BORDER_ROUTER_TLV,
252                                  NWD_BORDER_ROUTER_TLV,
253                                  NWD_6LOWPAN_ID_TLV
254                                 } <= set(p.thread_nwd.tlv.type) and\
255                       p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
256                       p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
257                       p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
258                       p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
259                       p.mle.tlv.leader_data.data_version ==
260                       (_dr_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
261                       (p.mle.tlv.leader_data.stable_data_version ==
262                        (_dr_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256 or\
263                       p.mle.tlv.leader_data.stable_data_version ==
264                        (_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256) and\
265                       [Ipv6Addr(PREFIX_2001[:-3])] ==
266                       p.thread_nwd.tlv.prefix
267                       ).\
268                must_next()
269
270        # Step 6: Leader MUST send a MLE Child Update Request or MLE Data
271        #         Response to SED, including the following TLVs:
272        #             - Network Data TLV
273        #                 At least one Prefix TLV (Prefix 1) including:
274        #                     - Border Router sub-TLV(corresponding to Router_1)
275        #                     - 6LoWPAN ID sub-TLV
276        #                         - P_border_router_16<0xFFFE>
277        #             - Source Address TLV
278        #             - Leader Data TLV
279        #                 Data version numbers should be the same as the ones
280        #                 sent in the multicast data response in step 5.
281        #             - Active Timestamp TLV
282        pkts.filter_wpan_src64(LEADER).\
283            filter_wpan_dst64(SED).\
284            filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
285            filter(lambda p: {
286                              NETWORK_DATA_TLV,
287                              SOURCE_ADDRESS_TLV,
288                              LEADER_DATA_TLV,
289                              ACTIVE_TIMESTAMP_TLV
290                             } <= set(p.mle.tlv.type) and\
291                   [Ipv6Addr(PREFIX_2001[:-3])] ==
292                   p.thread_nwd.tlv.prefix and\
293                   p.thread_nwd.tlv.stable == [1, 1, 1] and\
294                   p.mle.tlv.leader_data.data_version  ==
295                   _dr_pkt1.mle.tlv.leader_data.data_version and\
296                   p.mle.tlv.leader_data.stable_data_version  ==
297                   _dr_pkt1.mle.tlv.leader_data.stable_data_version and\
298                   [0xFFFE] == p.thread_nwd.tlv.border_router_16
299                   ).\
300            must_next()
301
302        # Step 8: Leader  MUST detect that Router_1 is removed from the network and
303        #         update the Router ID Set. Leader MUST remove the Network Data
304        #         section corresponding to Router_1 and increment the Data Version
305        #         and Stable Data Version
306
307        # Step 9: Leader MUST multicast MLE Data Response neighbors and rx-on-when-idle
308        #         Children (MED) including the following TLVs:,
309        #              - Source Address TLV
310        #              - Leader Data TLV
311        #                  - Data Version field <incremented>
312        #                  - Stable Data Version field <incremented>
313        #              - Network Data TLV
314        #                  - Router_1’s Network Data section MUST be removed
315        pkts.filter_wpan_src64(LEADER).\
316            filter_LLANMA().\
317            filter_mle_cmd(MLE_DATA_RESPONSE).\
318            filter(lambda p: {
319                              NETWORK_DATA_TLV,
320                              SOURCE_ADDRESS_TLV,
321                              LEADER_DATA_TLV,
322                             } <= set(p.mle.tlv.type) and\
323                   [Ipv6Addr(PREFIX_2001[:-3])] ==
324                   p.thread_nwd.tlv.prefix and\
325                   [ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16 and\
326                   p.mle.tlv.leader_data.data_version ==
327                   (_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\
328                   p.mle.tlv.leader_data.stable_data_version ==
329                   (_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256
330                   ).\
331            must_next()
332
333        # Step 10: The DUT MUST send a MLE Child Update Request or MLE Data
334        #         Response to SED, containing the updated Network Data:
335        #             - Network Data TLV
336        #             - Source Address TLV
337        #             - Active Timestamp TLV
338        _pkt = pkts.filter_wpan_src64(LEADER).\
339            filter_wpan_dst64(SED).\
340            filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
341            filter(lambda p: {
342                              NETWORK_DATA_TLV,
343                              SOURCE_ADDRESS_TLV,
344                              LEADER_DATA_TLV,
345                             } <= set(p.mle.tlv.type) and\
346                   [Ipv6Addr(PREFIX_2001[:-3])] ==
347                   p.thread_nwd.tlv.prefix and\
348                   p.thread_nwd.tlv.border_router_16 is nullField and\
349                   p.mle.tlv.leader_data.data_version ==
350                   (_dr_pkt1.mle.tlv.leader_data.data_version + 1) % 256 and\
351                   p.mle.tlv.leader_data.stable_data_version ==
352                   (_dr_pkt1.mle.tlv.leader_data.stable_data_version + 1) % 256
353                   ).\
354            must_next()
355
356        # Step 12: Leader MUST send MLE Child ID Response to Router_1, which
357        #          includes the following TLVs:
358        #              - Source Address TLV
359        #              - Leader Data TLV
360        #              - Address16 TLV
361        #              - Route64 TLV
362        #              - Network Data TLV
363        #                  - At least one Prefix TLV (Prefix 1)
364        #                    including:
365        #                        - Border Router sub-tlv corresponding to Router_2
366        #                        - 6LoWPAN ID sub-TLV
367        pkts.filter_wpan_src64(LEADER).\
368            filter_wpan_dst64(ROUTER_1).\
369            filter_mle_cmd(MLE_CHILD_ID_RESPONSE).\
370            filter(lambda p: {
371                              ADDRESS16_TLV,
372                              LEADER_DATA_TLV,
373                              NETWORK_DATA_TLV,
374                              SOURCE_ADDRESS_TLV,
375                              ROUTE64_TLV
376                              } <= set(p.mle.tlv.type) and\
377                             {
378                              NWD_BORDER_ROUTER_TLV,
379                              NWD_6LOWPAN_ID_TLV
380                             } <= set(p.thread_nwd.tlv.type) and\
381                   [Ipv6Addr(PREFIX_2001[:-3])] ==
382                   p.thread_nwd.tlv.prefix and\
383                   [ROUTER_2_RLOC16] == p.thread_nwd.tlv.border_router_16
384                   ).\
385             must_next()
386
387        # Step 13: Router_1 MUST send a CoAP Server DataNotification frame to
388        #          the Leader including the server’s information(Prefix, Border Router):
389        #             CoAP Request URI
390        #                 coap://[<Leader address>]:MM/a/sd
391        #             CoAP Payload
392        #                 Thread Network Data TLV
393
394        # Step 14: Leader sends a CoAP ACK frame to each of Router_1
395        with pkts.save_index():
396            pkts.filter_wpan_src64(ROUTER_1).\
397                filter_wpan_dst16(LEADER_RLOC16).\
398                filter_coap_request(SVR_DATA_URI).\
399                filter(lambda p:
400                       [Ipv6Addr(PREFIX_2001[:-3])] ==
401                       p.thread_nwd.tlv.prefix and\
402                       [ROUTER_1_RLOC16] ==
403                       p.thread_nwd.tlv.border_router_16
404                       ).\
405                must_next()
406            pkts.filter_wpan_src64(LEADER).\
407                filter_ipv6_dst(ROUTER_1_RLOC).\
408                filter_coap_ack(SVR_DATA_URI).\
409                must_next()
410
411        # Step 15: Leader MUST multicast MLE Data Response with the new
412        #         information collected from Router_1 and Router_2,
413        #         including the following TLVs:,
414        #              - Source Address TLV
415        #              - Leader Data TLV
416        #                  - Data Version field <incremented>
417        #                  - Stable Data Version field <incremented>
418        #              - Network Data TLV
419        #                  - At least one Prefix TLV (Prefix 1)
420        #                      - Two Border Router sub-TLVs
421        #                        corresponding to Router_1 and Router_2
422        #                      - 6LoWPAN ID sub-TLV
423        _dr_pkt2 = pkts.filter_wpan_src64(LEADER).\
424            filter_LLANMA().\
425            filter_mle_cmd(MLE_DATA_RESPONSE).\
426            filter(lambda p: {
427                              NETWORK_DATA_TLV,
428                              SOURCE_ADDRESS_TLV,
429                              LEADER_DATA_TLV
430                             } <= set(p.mle.tlv.type) and\
431                   {ROUTER_1_RLOC16, ROUTER_2_RLOC16} ==
432                   set(p.thread_nwd.tlv.border_router_16) and\
433                   [Ipv6Addr(PREFIX_2001[:-3])] ==
434                   p.thread_nwd.tlv.prefix and\
435                   p.mle.tlv.leader_data.data_version ==
436                   (_pkt.mle.tlv.leader_data.data_version + 1) % 256 and\
437                   p.mle.tlv.leader_data.stable_data_version ==
438                   (_pkt.mle.tlv.leader_data.stable_data_version + 1) % 256
439                   ).\
440            must_next()
441
442        # Step 16: Leader MUST send a MLE Child Update Request or MLE Data
443        #          Response to SED, including the following TLVs:
444        #              - Network Data TLV
445        #                 At least one Prefix TLV (Prefix 1)
446        #                     - Border Router TLV (corresponding to Router_1)
447        #                     - 6LoWPAN ID sub-TLV
448        #                         - P_border_router_16<0xFFFE>
449        #              - Source Address TLV
450        #              - Leader Data TLV
451        #                 Data version numbers should be the same as those
452        #                 sent in the multicast data response in step 15.
453        #              - Active Timestamp TLV
454        pkts.filter_wpan_src64(LEADER).\
455            filter_wpan_dst64(SED).\
456            filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
457            filter(lambda p: {
458                              NETWORK_DATA_TLV,
459                              SOURCE_ADDRESS_TLV,
460                              LEADER_DATA_TLV,
461                              ACTIVE_TIMESTAMP_TLV
462                             } <= set(p.mle.tlv.type) and\
463                   [Ipv6Addr(PREFIX_2001[:-3])] ==
464                   p.thread_nwd.tlv.prefix and\
465                   p.mle.tlv.leader_data.data_version  ==
466                   _dr_pkt2.mle.tlv.leader_data.data_version and\
467                   p.thread_nwd.tlv.stable == [1, 1, 1] and\
468                   [0xFFFE] == p.thread_nwd.tlv.border_router_16
469                   ).\
470            must_next()
471
472        # Step 17: Verifies connectivity by sending ICMPv6 Echo Requests from
473        #          Router_1 and SED_1 to the Leader Prefix_1 based address.
474        #          Leader must respond with ICMPv6 Echo Replies
475        for node in ('ROUTER_1', 'SED'):
476            _pkt = pkts.filter_ping_request().\
477                filter_ipv6_src_dst(GUA[node], GUA['LEADER']).\
478                must_next()
479            pkts.filter_ping_reply(identifier=_pkt.icmpv6.echo.identifier).\
480                filter_ipv6_src_dst(GUA['LEADER'], GUA[node]).\
481                must_next()
482
483
484if __name__ == '__main__':
485    unittest.main()
486