1#!/usr/bin/env python3
2#
3#  Copyright (c) 2016, The OpenThread Authors.
4#  All rights reserved.
5#
6#  Redistribution and use in source and binary forms, with or without
7#  modification, are permitted provided that the following conditions are met:
8#  1. Redistributions of source code must retain the above copyright
9#     notice, this list of conditions and the following disclaimer.
10#  2. Redistributions in binary form must reproduce the above copyright
11#     notice, this list of conditions and the following disclaimer in the
12#     documentation and/or other materials provided with the distribution.
13#  3. Neither the name of the copyright holder nor the
14#     names of its contributors may be used to endorse or promote products
15#     derived from this software without specific prior written permission.
16#
17#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18#  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19#  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20#  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21#  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22#  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23#  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24#  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25#  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26#  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27#  POSSIBILITY OF SUCH DAMAGE.
28#
29
30import unittest
31
32import config
33import thread_cert
34from pktverify.consts import MLE_ADVERTISEMENT, MLE_CHILD_ID_RESPONSE, MLE_DATA_REQUEST, MLE_DATA_RESPONSE, TLV_REQUEST_TLV, NETWORK_DATA_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV
35from pktverify.packet_verifier import PacketVerifier
36
37LEADER = 1
38ROUTER1 = 2
39ROUTER2 = 3
40ROUTER3 = 4
41ROUTER15 = 16
42REED1 = 17
43
44
45class Cert_5_6_7_NetworkDataRequestREED(thread_cert.TestCase):
46    TOPOLOGY = {
47        LEADER: {
48            'name': 'LEADER',
49            'mode': 'rdn',
50            'allowlist': [ROUTER1, ROUTER2, ROUTER3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ROUTER15]
51        },
52        ROUTER1: {
53            'name': 'ROUTER_1',
54            'mode': 'rdn',
55            'allowlist': [LEADER]
56        },
57        ROUTER2: {
58            'name': 'ROUTER_2',
59            'mode': 'rdn',
60            'allowlist': [LEADER, REED1]
61        },
62        ROUTER3: {
63            'mode': 'rdn',
64            'allowlist': [LEADER]
65        },
66        5: {
67            'mode': 'rdn',
68            'allowlist': [LEADER]
69        },
70        6: {
71            'mode': 'rdn',
72            'allowlist': [LEADER]
73        },
74        7: {
75            'mode': 'rdn',
76            'allowlist': [LEADER]
77        },
78        8: {
79            'mode': 'rdn',
80            'allowlist': [LEADER]
81        },
82        9: {
83            'mode': 'rdn',
84            'allowlist': [LEADER]
85        },
86        10: {
87            'mode': 'rdn',
88            'allowlist': [LEADER]
89        },
90        11: {
91            'mode': 'rdn',
92            'allowlist': [LEADER]
93        },
94        12: {
95            'mode': 'rdn',
96            'allowlist': [LEADER]
97        },
98        13: {
99            'mode': 'rdn',
100            'allowlist': [LEADER]
101        },
102        14: {
103            'mode': 'rdn',
104            'allowlist': [LEADER]
105        },
106        15: {
107            'mode': 'rdn',
108            'allowlist': [LEADER]
109        },
110        ROUTER15: {
111            'mode': 'rdn',
112            'allowlist': [LEADER]
113        },
114        REED1: {
115            'name': 'REED',
116            'mode': 'rdn',
117            'allowlist': [ROUTER2]
118        },
119    }
120
121    def test(self):
122        self.nodes[LEADER].start()
123        self.simulator.go(config.LEADER_STARTUP_DELAY)
124        self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
125
126        for i in range(ROUTER1, ROUTER15 + 1):
127            self.nodes[i].start()
128            self.simulator.go(config.ROUTER_STARTUP_DELAY)
129            self.assertEqual(self.nodes[i].get_state(), 'router')
130
131        self.nodes[REED1].start()
132        self.simulator.go(5)
133        self.assertEqual(self.nodes[REED1].get_state(), 'child')
134
135        self.nodes[ROUTER2].remove_allowlist(self.nodes[REED1].get_addr64())
136        self.nodes[REED1].remove_allowlist(self.nodes[ROUTER2].get_addr64())
137
138        self.nodes[LEADER].add_prefix('2001:2:0:3::/64', 'paros')
139        self.nodes[LEADER].register_netdata()
140
141        # Set lowpan context of sniffer
142        self.simulator.set_lowpan_context(1, '2001:2:0:3::/64')
143
144        self.simulator.go(2)
145
146        self.nodes[ROUTER2].add_allowlist(self.nodes[REED1].get_addr64())
147        self.nodes[REED1].add_allowlist(self.nodes[ROUTER2].get_addr64())
148
149        self.simulator.go(30)
150        self.simulator.go(600)
151
152        addrs = self.nodes[REED1].get_addrs()
153        self.assertTrue(any('2001:2:0:3' in addr[0:10] for addr in addrs))
154        for addr in addrs:
155            if addr[0:10] == '2001:2:0:3':
156                self.assertTrue(self.nodes[LEADER].ping(addr))
157
158    def verify(self, pv):
159        pkts = pv.pkts
160        pv.summary.show()
161
162        LEADER = pv.vars['LEADER']
163        REED = pv.vars['REED']
164
165        # Step 4: Leader multicasts a MLE Data Response with the new information
166        _pkt = pkts.filter_mle_cmd(MLE_CHILD_ID_RESPONSE).filter_wpan_dst64(REED).must_next()
167        pkts.filter_wpan_src64(LEADER).filter_mle_cmd(MLE_DATA_RESPONSE).must_next().must_verify(
168            lambda p: {NWD_PREFIX_TLV, NWD_BORDER_ROUTER_TLV, NWD_6LOWPAN_ID_TLV} <= set(p.thread_nwd.tlv.type))
169
170        # Step 8: REED1 MUST send a MLE Data Request to its parent to get the new Network Dataset.
171        # MLE Data Request includes a TLV Request TLV for Network Data TLV
172        pkts.filter_wpan_src64(REED).filter_mle_cmd(MLE_DATA_REQUEST).must_next().must_verify(
173            lambda p: {TLV_REQUEST_TLV, NETWORK_DATA_TLV} <= set(p.mle.tlv.type))
174
175        # Step 10: REED1 send MLE Advertisement
176        pkts.filter_wpan_src64(REED).filter_mle_cmd(MLE_ADVERTISEMENT).must_next().must_verify(
177            lambda p: p.mle.tlv.leader_data.data_version == (_pkt.mle.tlv.leader_data.data_version + 1) % 256)
178
179
180if __name__ == '__main__':
181    unittest.main()
182