1 /*
2 * Copyright (c) 2019, The OpenThread Authors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the copyright holder nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdarg.h>
30
31 #include "test_platform.h"
32
33 #include <openthread/config.h>
34
35 #include "common/code_utils.hpp"
36 #include "common/debug.hpp"
37 #include "common/instance.hpp"
38 #include "net/netif.hpp"
39
40 #include "test_util.h"
41
42 namespace ot {
43
44 class TestNetif : public Ip6::Netif
45 {
46 public:
TestNetif(Instance & aInstance)47 explicit TestNetif(Instance &aInstance)
48 : Ip6::Netif(aInstance)
49 {
50 }
51
52 // Provide `protected` methods in `Netif` as `public` from `TestNetif`
53 // so that we can verify their behavior in this test
SubscribeAllNodesMulticast(void)54 void SubscribeAllNodesMulticast(void) { Ip6::Netif::SubscribeAllNodesMulticast(); }
UnsubscribeAllNodesMulticast(void)55 void UnsubscribeAllNodesMulticast(void) { Ip6::Netif::UnsubscribeAllNodesMulticast(); }
56 };
57
58 // This function verifies the multicast addresses on Netif matches the list of given addresses.
VerifyMulticastAddressList(const Ip6::Netif & aNetif,Ip6::Address aAddresses[],uint8_t aLength)59 void VerifyMulticastAddressList(const Ip6::Netif &aNetif, Ip6::Address aAddresses[], uint8_t aLength)
60 {
61 uint8_t count = 0;
62
63 for (uint8_t i = 0; i < aLength; i++)
64 {
65 VerifyOrQuit(aNetif.IsMulticastSubscribed(aAddresses[i]));
66 }
67
68 for (const Ip6::Netif::MulticastAddress &addr : aNetif.GetMulticastAddresses())
69 {
70 bool didFind = false;
71
72 for (uint8_t i = 0; i < aLength; i++)
73 {
74 if (addr.GetAddress() == aAddresses[i])
75 {
76 didFind = true;
77 break;
78 }
79 }
80
81 VerifyOrQuit(didFind, "Netif multicast address is missing from expected address list");
82 count++;
83 }
84
85 VerifyOrQuit(count == aLength, "Expected address is missing from Netif address list");
86 }
87
TestNetifMulticastAddresses(void)88 void TestNetifMulticastAddresses(void)
89 {
90 const uint8_t kMaxAddresses = 8;
91
92 Instance * instance = testInitInstance();
93 TestNetif netif(*instance);
94 Ip6::Address addresses[kMaxAddresses];
95
96 Ip6::Address address;
97 Ip6::Netif::MulticastAddress netifAddress;
98
99 const char *kLinkLocalAllNodes = "ff02::01";
100 const char *kRealmLocalAllNodes = "ff03::01";
101 const char *kRealmLocalAllMpl = "ff03::fc";
102 const char *kLinkLocalAllRouters = "ff02::02";
103 const char *kRealmLocalAllRouters = "ff03::02";
104 const char *kTestAddress1 = "ff02::114";
105 const char *kTestAddress2 = "ff03::114";
106 const char *kTestAddress3 = "ff04::114";
107
108 IgnoreError(addresses[0].FromString(kLinkLocalAllRouters));
109 IgnoreError(addresses[1].FromString(kRealmLocalAllRouters));
110 IgnoreError(addresses[2].FromString(kLinkLocalAllNodes));
111 IgnoreError(addresses[3].FromString(kRealmLocalAllNodes));
112 IgnoreError(addresses[4].FromString(kRealmLocalAllMpl));
113 IgnoreError(addresses[5].FromString(kTestAddress1));
114 IgnoreError(addresses[6].FromString(kTestAddress2));
115 IgnoreError(addresses[7].FromString(kTestAddress3));
116
117 VerifyMulticastAddressList(netif, addresses, 0);
118
119 netif.SubscribeAllNodesMulticast();
120 VerifyMulticastAddressList(netif, &addresses[2], 3);
121
122 netif.SubscribeAllNodesMulticast();
123 VerifyMulticastAddressList(netif, &addresses[2], 3);
124
125 netif.SubscribeAllRoutersMulticast();
126 VerifyMulticastAddressList(netif, &addresses[0], 5);
127
128 netif.SubscribeAllRoutersMulticast();
129 VerifyMulticastAddressList(netif, &addresses[0], 5);
130
131 netif.UnsubscribeAllRoutersMulticast();
132 VerifyMulticastAddressList(netif, &addresses[2], 3);
133
134 netif.UnsubscribeAllRoutersMulticast();
135 VerifyMulticastAddressList(netif, &addresses[2], 3);
136
137 IgnoreError(netifAddress.GetAddress().FromString(kTestAddress1));
138 netif.SubscribeMulticast(netifAddress);
139 VerifyMulticastAddressList(netif, &addresses[2], 4);
140
141 netif.SubscribeMulticast(netifAddress);
142 VerifyMulticastAddressList(netif, &addresses[2], 4);
143
144 netif.UnsubscribeAllNodesMulticast();
145 VerifyMulticastAddressList(netif, &addresses[5], 1);
146
147 netif.UnsubscribeAllNodesMulticast();
148 VerifyMulticastAddressList(netif, &addresses[5], 1);
149
150 IgnoreError(address.FromString(kTestAddress2));
151 SuccessOrQuit(netif.SubscribeExternalMulticast(address));
152 VerifyMulticastAddressList(netif, &addresses[5], 2);
153
154 netif.SubscribeAllNodesMulticast();
155 VerifyMulticastAddressList(netif, &addresses[2], 5);
156
157 netif.SubscribeAllNodesMulticast();
158 VerifyMulticastAddressList(netif, &addresses[2], 5);
159
160 netif.SubscribeAllRoutersMulticast();
161 VerifyMulticastAddressList(netif, &addresses[0], 7);
162
163 netif.SubscribeAllRoutersMulticast();
164 VerifyMulticastAddressList(netif, &addresses[0], 7);
165
166 IgnoreError(address.FromString(kTestAddress3));
167 SuccessOrQuit(netif.SubscribeExternalMulticast(address));
168 VerifyMulticastAddressList(netif, &addresses[0], 8);
169
170 IgnoreError(address.FromString(kTestAddress1)); // same as netifAddress (internal)
171 VerifyOrQuit(netif.UnsubscribeExternalMulticast(address) == kErrorInvalidArgs,
172 "UnsubscribeExternalMulticast() did not fail when address was not external");
173
174 IgnoreError(address.FromString(kRealmLocalAllMpl));
175 VerifyOrQuit(netif.UnsubscribeExternalMulticast(address) == kErrorInvalidArgs,
176 "UnsubscribeExternalMulticast() did not fail when address was fixed address");
177
178 netif.UnsubscribeAllRoutersMulticast();
179 VerifyMulticastAddressList(netif, &addresses[2], 6);
180
181 netif.UnsubscribeAllRoutersMulticast();
182 VerifyMulticastAddressList(netif, &addresses[2], 6);
183
184 netif.UnsubscribeAllExternalMulticastAddresses();
185 VerifyMulticastAddressList(netif, &addresses[2], 4);
186
187 netif.UnsubscribeMulticast(netifAddress);
188 VerifyMulticastAddressList(netif, &addresses[2], 3);
189
190 netif.UnsubscribeMulticast(netifAddress);
191 VerifyMulticastAddressList(netif, &addresses[2], 3);
192
193 netif.UnsubscribeAllNodesMulticast();
194 VerifyMulticastAddressList(netif, nullptr, 0);
195
196 // The first five elements in `addresses[]` are the default/fixed addresses:
197 // kLinkLocalAllRouters, kRealmLocalAllRouters, kLinkLocalAllNodes,
198 // kRealmLocalAllNodes, and kRealmLocalAllMpl. Verify that we cannot add
199 // any of them as an external multicast address.
200
201 for (uint8_t i = 0; i < 5; i++)
202 {
203 VerifyOrQuit(netif.SubscribeExternalMulticast(addresses[i]) == kErrorInvalidArgs,
204 "SubscribeExternalMulticast() did not fail when address was a default/fixed address");
205 }
206 }
207
208 } // namespace ot
209
main(void)210 int main(void)
211 {
212 ot::TestNetifMulticastAddresses();
213 printf("All tests passed\n");
214 return 0;
215 }
216