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
31import copy
32
33import config
34import thread_cert
35from pktverify.consts import WIRESHARK_OVERRIDE_PREFS, MLE_CHILD_UPDATE_REQUEST, MLE_CHILD_UPDATE_RESPONSE, MLE_DATA_RESPONSE, MLE_CHILD_ID_REQUEST, MLE_CHILD_ID_RESPONSE, ACTIVE_TIMESTAMP_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, MODE_TLV, TIMEOUT_TLV, VERSION_TLV, TLV_REQUEST_TLV, ADDRESS16_TLV, NETWORK_DATA_TLV, ROUTE64_TLV, MODE_TLV, TIMEOUT_TLV, CHALLENGE_TLV, SOURCE_ADDRESS_TLV, LEADER_DATA_TLV, ADDRESS_REGISTRATION_TLV
36from pktverify.packet_verifier import PacketVerifier
37from pktverify.addrs import Ipv6Addr
38from pktverify.null_field import nullField
39
40LEADER = 1
41ROUTER = 2
42SED1 = 3
43MED1 = 4
44
45MTDS = [SED1, MED1]
46PREFIX_2001 = '2001::/64'
47PREFIX_2002 = '2002::/64'
48
49# Test Purpose and Description:
50# -----------------------------
51# The purpose of this test case is to verify that global prefix information can
52# be set on the DUT, which is acting as a Leader in the Thread network. The DUT
53# must also demonstrate that it correctly sets the Network Data (stable/non-stable)
54# and propagates it properly in an already formed network.
55#
56# Test Topology:
57# -------------
58#             SED
59#              |
60#  ROUTER - Leader(DUT) - MED
61#
62# DUT Types:
63# ----------
64#  Leader
65
66
67class Cert_7_1_3_BorderRouterAsLeader(thread_cert.TestCase):
68    USE_MESSAGE_FACTORY = False
69
70    TOPOLOGY = {
71        LEADER: {
72            'name': 'LEADER',
73            'mode': 'rdn',
74            'allowlist': [ROUTER, SED1, MED1]
75        },
76        ROUTER: {
77            'name': 'ROUTER',
78            'mode': 'rdn',
79            'allowlist': [LEADER]
80        },
81        SED1: {
82            'name': 'SED',
83            'is_mtd': True,
84            'mode': '-',
85            'timeout': config.DEFAULT_CHILD_TIMEOUT,
86            'allowlist': [LEADER]
87        },
88        MED1: {
89            'name': 'MED',
90            'is_mtd': True,
91            'mode': 'rn',
92            'allowlist': [LEADER]
93        },
94    }
95    # override wireshark preferences with case needed parameters
96    CASE_WIRESHARK_PREFS = copy.deepcopy(WIRESHARK_OVERRIDE_PREFS)
97    CASE_WIRESHARK_PREFS['6lowpan.context1'] = PREFIX_2001
98    CASE_WIRESHARK_PREFS['6lowpan.context2'] = PREFIX_2002
99
100    def test(self):
101        self.nodes[LEADER].start()
102        self.simulator.go(5)
103        self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
104
105        self.nodes[ROUTER].start()
106        self.simulator.go(5)
107        self.assertEqual(self.nodes[ROUTER].get_state(), 'router')
108
109        self.nodes[SED1].start()
110        self.simulator.go(5)
111        self.assertEqual(self.nodes[SED1].get_state(), 'child')
112
113        self.nodes[MED1].start()
114        self.simulator.go(5)
115        self.assertEqual(self.nodes[MED1].get_state(), 'child')
116
117        self.nodes[LEADER].add_prefix(PREFIX_2001, 'paros')
118        self.nodes[LEADER].add_prefix(PREFIX_2002, 'paro')
119        self.nodes[LEADER].register_netdata()
120        self.simulator.go(5)
121
122    def verify(self, pv):
123        pkts = pv.pkts
124        pv.summary.show()
125
126        LEADER = pv.vars['LEADER']
127        ROUTER = pv.vars['ROUTER']
128        SED = pv.vars['SED']
129        MED = pv.vars['MED']
130
131        # Step 1: Ensure topology is formed correctly
132        pv.verify_attached('ROUTER', 'LEADER')
133        pv.verify_attached('SED', 'LEADER', 'MTD')
134        pv.verify_attached('MED', 'LEADER', 'MTD')
135
136        # Step 3: The DUT MUST send a multicast MLE Data Response,
137        #         including the following TLVs:
138        #             - Network Data TLV
139        #               At least two Prefix TLVs (Prefix 1 and Prefix 2),
140        #               each including:
141        #                   - 6LoWPAN ID sub-TLV
142        #                   - Border Router sub-TLV
143        pkts.filter_wpan_src64(LEADER).\
144            filter_LLANMA().\
145            filter_mle_cmd(MLE_DATA_RESPONSE).\
146            filter(lambda p: {
147                              Ipv6Addr(PREFIX_2001[:-3]),
148                              Ipv6Addr(PREFIX_2002[:-3])
149                             } == set(p.thread_nwd.tlv.prefix) and\
150                   p.thread_nwd.tlv.border_router.flag.p == [1, 1] and\
151                   p.thread_nwd.tlv.border_router.flag.s == [1, 1] and\
152                   p.thread_nwd.tlv.border_router.flag.r == [1, 1] and\
153                   p.thread_nwd.tlv.border_router.flag.o == [1, 1] and\
154                   p.thread_nwd.tlv.stable == [0, 1, 1, 1, 0, 0, 0]
155                   ).\
156            must_next()
157
158        # Step 4: MED automatically sends the global address configured to its parent
159        #         (the DUT), via the Address Registration TLV included in its Child
160        #         Update Request keep-alive message.
161
162        # Step 5: The DUT MUST send a MLE Child Update Response to MED
163        #          The following TLVs MUST be present in the Child Update Response:
164        #              - Source Address TLV
165        #              - Address Registration TLV
166        #                  - Echoes back addresses configured in step 4
167        #              - Mode TLV
168        with pkts.save_index():
169            _pkt = pkts.filter_wpan_src64(MED).\
170                filter_wpan_dst64(LEADER).\
171                filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
172                must_next()
173            pkts.filter_wpan_src64(LEADER).\
174                filter_wpan_dst64(MED).\
175                filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
176                filter(lambda p: {
177                                  SOURCE_ADDRESS_TLV,
178                                  MODE_TLV,
179                                  ADDRESS_REGISTRATION_TLV
180                                 } < set(p.mle.tlv.type) and\
181                       p.mle.tlv.addr_reg_iid is not nullField and\
182                       set(_pkt.mle.tlv.addr_reg_iid) > set(p.mle.tlv.addr_reg_iid)
183                       ).\
184                must_next()
185
186        # Step 6: The DUT MUST send a MLE Child Update Request or MLE Data
187        #         Response to SED, including the following TLVs:
188        #             - Network Data TLV
189        #             - Source Address TLV
190        #             - Leader Data TLV
191        #             - Active Timestamp TLV
192        pkts.filter_wpan_src64(LEADER).\
193            filter_wpan_dst64(SED).\
194            filter_mle_cmd2(MLE_CHILD_UPDATE_REQUEST, MLE_DATA_RESPONSE).\
195            filter(lambda p: {
196                              NETWORK_DATA_TLV,
197                              SOURCE_ADDRESS_TLV,
198                              LEADER_DATA_TLV,
199                              ACTIVE_TIMESTAMP_TLV
200                             } == set(p.mle.tlv.type) and\
201                   [Ipv6Addr(PREFIX_2001[:-3])] == p.thread_nwd.tlv.prefix and\
202                   p.thread_nwd.tlv.border_router.flag.p == [1] and\
203                   p.thread_nwd.tlv.border_router.flag.s == [1] and\
204                   p.thread_nwd.tlv.border_router.flag.r == [1] and\
205                   p.thread_nwd.tlv.border_router.flag.o == [1] and\
206                   p.thread_nwd.tlv.stable == [1, 1, 1]
207                   ).\
208            must_next()
209
210        # Step 9: After receiving the MLE Data Response or MLE Child Update Request,
211        #         SED automatically sends its global address configured to the Leader,
212        #         in the Address Registration TLV from the Child Update request command
213
214        # Step 10: The DUT MUST send a MLE Child Update Response, each, to SED
215        #          The following TLVs MUST be present in the Child Update Response:
216        #              - Source Address TLV
217        #              - Address Registration TLV
218        #                  - Echoes back addresses configured in step 9
219        #              - Mode TLV
220        _pkt = pkts.filter_wpan_src64(SED).\
221            filter_wpan_dst64(LEADER).\
222            filter_mle_cmd(MLE_CHILD_UPDATE_REQUEST).\
223            must_next()
224        pkts.filter_wpan_src64(LEADER).\
225            filter_wpan_dst64(SED).\
226            filter_mle_cmd(MLE_CHILD_UPDATE_RESPONSE).\
227            filter(lambda p: {
228                              SOURCE_ADDRESS_TLV,
229                              MODE_TLV,
230                              ADDRESS_REGISTRATION_TLV
231                             } < set(p.mle.tlv.type) and\
232                   p.mle.tlv.addr_reg_iid is not nullField and\
233                   set(_pkt.mle.tlv.addr_reg_iid) > set(p.mle.tlv.addr_reg_iid)
234                   ).\
235            must_next()
236
237
238if __name__ == '__main__':
239    unittest.main()
240