1 /*
2 * Copyright (c) 2023, 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 /**
30 * @file
31 * This file implements CLI for MAC Filter.
32 */
33
34 #include "cli_mac_filter.hpp"
35
36 #include "cli/cli.hpp"
37
38 #if OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
39
40 namespace ot {
41 namespace Cli {
42
OutputFilter(uint8_t aFilters)43 void MacFilter::OutputFilter(uint8_t aFilters)
44 {
45 otMacFilterEntry entry;
46 otMacFilterIterator iterator;
47
48 if (aFilters & kAddressFilter)
49 {
50 if ((aFilters & ~kAddressFilter) != 0)
51 {
52 OutputFormat("Address Mode: ");
53 }
54
55 OutputLine("%s", AddressModeToString(otLinkFilterGetAddressMode(GetInstancePtr())));
56
57 iterator = OT_MAC_FILTER_ITERATOR_INIT;
58
59 while (otLinkFilterGetNextAddress(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
60 {
61 OutputEntry(entry);
62 }
63 }
64
65 if (aFilters & kRssFilter)
66 {
67 if ((aFilters & ~kRssFilter) != 0)
68 {
69 OutputLine("RssIn List:");
70 }
71
72 iterator = OT_MAC_FILTER_ITERATOR_INIT;
73
74 while (otLinkFilterGetNextRssIn(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
75 {
76 if (IsDefaultRss(entry.mExtAddress))
77 {
78 OutputLine("Default rss: %d (lqi %u)", entry.mRssIn,
79 otLinkConvertRssToLinkQuality(GetInstancePtr(), entry.mRssIn));
80 }
81 else
82 {
83 OutputEntry(entry);
84 }
85 }
86 }
87 }
88
IsDefaultRss(const otExtAddress & aExtAddress)89 bool MacFilter::IsDefaultRss(const otExtAddress &aExtAddress)
90 {
91 // In default RSS entry, the extended address will be all `0xff`.
92
93 bool isDefault = true;
94
95 for (uint8_t byte : aExtAddress.m8)
96 {
97 if (byte != 0xff)
98 {
99 isDefault = false;
100 break;
101 }
102 }
103
104 return isDefault;
105 }
106
AddressModeToString(otMacFilterAddressMode aMode)107 const char *MacFilter::AddressModeToString(otMacFilterAddressMode aMode)
108 {
109 static const char *const kModeStrings[] = {
110 "Disabled", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED
111 "Allowlist", // (1) OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST
112 "Denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST
113 };
114
115 static_assert(0 == OT_MAC_FILTER_ADDRESS_MODE_DISABLED, "OT_MAC_FILTER_ADDRESS_MODE_DISABLED value is incorrect");
116 static_assert(1 == OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST, "OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST value is incorrect");
117 static_assert(2 == OT_MAC_FILTER_ADDRESS_MODE_DENYLIST, "OT_MAC_FILTER_ADDRESS_MODE_DENYLIST value is incorrect");
118
119 return Stringify(aMode, kModeStrings);
120 }
121
OutputEntry(const otMacFilterEntry & aEntry)122 void MacFilter::OutputEntry(const otMacFilterEntry &aEntry)
123 {
124 OutputExtAddress(aEntry.mExtAddress);
125
126 if (aEntry.mRssIn != OT_MAC_FILTER_FIXED_RSS_DISABLED)
127 {
128 OutputFormat(" : rss %d (lqi %d)", aEntry.mRssIn,
129 otLinkConvertRssToLinkQuality(GetInstancePtr(), aEntry.mRssIn));
130 }
131
132 OutputNewLine();
133 }
134
Process(Arg aArgs[])135 template <> otError MacFilter::Process<Cmd("addr")>(Arg aArgs[])
136 {
137 otError error = OT_ERROR_NONE;
138 otExtAddress extAddr;
139
140 /**
141 * @cli macfilter addr
142 * @code
143 * macfilter addr
144 * Allowlist
145 * 0f6127e33af6b403 : rss -95 (lqi 1)
146 * 0f6127e33af6b402
147 * Done
148 * @endcode
149 * @par
150 * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled.
151 * @par
152 * Provides the following information:
153 * - Current mode of the MAC filter list: Either `AllowList`, `DenyList,` or `Disabled`
154 * - A list of all the extended addresses in the filter. The received signal strength (rss) and
155 * link quality indicator (lqi) are listed next to the address if these values have been set to be
156 * different from the default values.
157 * @sa otLinkFilterGetAddressMode
158 */
159 if (aArgs[0].IsEmpty())
160 {
161 OutputFilter(kAddressFilter);
162 }
163 /**
164 * @cli macfilter addr add
165 * @code
166 * macfilter addr add 0f6127e33af6b403 -95
167 * Done
168 * @endcode
169 * @code
170 * macfilter addr add 0f6127e33af6b402
171 * Done
172 * @endcode
173 * @cparam macfilter addr add @ca{extaddr} [@ca{rss}]
174 * @par
175 * Is available only when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled.
176 * @par
177 * Adds an IEEE 802.15.4 Extended Address to the MAC filter list.
178 * If you specify the optional `rss` argument, this fixes the received signal strength for messages from the
179 * address. If you do not use the `rss` option, the address will use whatever default value you have set.
180 * If you have not set a default, the signal strength will be the over-air signal.
181 * @sa otLinkFilterAddAddress
182 */
183 else if (aArgs[0] == "add")
184 {
185 SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8));
186 error = otLinkFilterAddAddress(GetInstancePtr(), &extAddr);
187
188 VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY);
189
190 if (!aArgs[2].IsEmpty())
191 {
192 int8_t rss;
193
194 SuccessOrExit(error = aArgs[2].ParseAsInt8(rss));
195 SuccessOrExit(error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss));
196 }
197 }
198 /**
199 * @cli macfilter addr remove
200 * @code
201 * macfilter addr remove 0f6127e33af6b402
202 * Done
203 * @endcode
204 * @cparam macfilter addr remove @ca{extaddr}
205 * @par
206 * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled.
207 * @par
208 * This command removes the specified extended address from the MAC filter list.
209 * @note No action is performed if the specified extended address does not match an entry in the MAC filter list.
210 * @sa otLinkFilterRemoveAddress
211 */
212 else if (aArgs[0] == "remove")
213 {
214 SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8));
215 otLinkFilterRemoveAddress(GetInstancePtr(), &extAddr);
216 }
217 /**
218 * @cli macfilter addr clear
219 * @code
220 * macfilter addr clear
221 * Done
222 * @endcode
223 * @par
224 * Is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled.
225 * @par
226 * This command clears all the extended addresses from the MAC filter list.
227 * @note This command does not affect entries in the `RssIn` list. That list contains extended addresses where the
228 * `rss` has been set to a fixed value that differs from the default.
229 * @sa otLinkFilterClearAddresses
230 */
231 else if (aArgs[0] == "clear")
232 {
233 otLinkFilterClearAddresses(GetInstancePtr());
234 }
235 else
236 {
237 static const char *const kModeCommands[] = {
238 /**
239 * @cli macfilter addr disable
240 * @code
241 * macfilter addr disable
242 * Done
243 * @endcode
244 * @par
245 * Disables MAC filter modes.
246 */
247 "disable", // (0) OT_MAC_FILTER_ADDRESS_MODE_DISABLED
248 /**
249 * @cli macfilter addr allowlist
250 * @code
251 * macfilter addr allowlist
252 * Done
253 * @endcode
254 * @par
255 * Enables the `allowlist` MAC filter mode, which means that only the MAC addresses in the MAC filter list
256 * will be allowed access.
257 * @sa otLinkFilterSetAddressMode
258 */
259 "allowlist", // (1) OT_MAC_FILTER_ADDRESS_MODE_ALLOWLIST
260 /**
261 * @cli macfilter addr denylist
262 * @code
263 * macfilter addr denylist
264 * Done
265 * @endcode
266 * @par
267 * Enables the `denylist` MAC filter mode, which means that all MAC addresses in the MAC filter list
268 * will be denied access.
269 * @sa otLinkFilterSetAddressMode
270 */
271 "denylist", // (2) OT_MAC_FILTER_ADDRESS_MODE_DENYLIST
272 };
273
274 for (size_t index = 0; index < OT_ARRAY_LENGTH(kModeCommands); index++)
275 {
276 if (aArgs[0] == kModeCommands[index])
277 {
278 VerifyOrExit(aArgs[1].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
279 otLinkFilterSetAddressMode(GetInstancePtr(), static_cast<otMacFilterAddressMode>(index));
280 ExitNow();
281 }
282 }
283
284 error = OT_ERROR_INVALID_COMMAND;
285 }
286
287 exit:
288 return error;
289 }
290
291 /**
292 * @cli macfilter rss
293 * @code
294 * macfilter rss
295 * 0f6127e33af6b403 : rss -95 (lqi 1)
296 * Default rss: -50 (lqi 3)
297 * Done
298 * @endcode
299 * @par
300 * Provides the following information:
301 * - Listing of all the extended addresses
302 * where the received signal strength (`rss`) has been set to be different from
303 * the default value. The link quality indicator (`lqi`) is also shown. The `rss`
304 * and `lqi` settings map to each other. If you set one, the value of the other
305 * gets set automatically. This list of addresses is called the `RssIn List`.
306 * Setting either the `rsi` or the `lqi` adds the corresponding extended address
307 * to the `RssIn` list.
308 * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings.
309 * @sa otLinkFilterGetNextRssIn
310 */
Process(Arg aArgs[])311 template <> otError MacFilter::Process<Cmd("rss")>(Arg aArgs[])
312 {
313 otError error = OT_ERROR_NONE;
314 otExtAddress extAddr;
315 int8_t rss;
316
317 if (aArgs[0].IsEmpty())
318 {
319 OutputFilter(kRssFilter);
320 }
321 /**
322 * @cli macfilter rss add-lqi
323 * @code
324 * macfilter rss add-lqi * 3
325 * Done
326 * @endcode
327 * @code
328 * macfilter rss add-lqi 0f6127e33af6b404 2
329 * Done
330 * @endcode
331 * @cparam macfilter rss add-lqi @ca{extaddr} @ca{lqi}
332 * To set a default value for the link quality indicator for all received messages,
333 * use the `*` for the `extaddr` argument. The allowed range is 0 to 3.
334 * @par
335 * Adds the specified Extended Address to the `RssIn` list (or modifies an existing address in the `RssIn` list)
336 * and sets the fixed link quality indicator for messages from that address.
337 * The Extended Address
338 * does not necessarily have to be in the `address allowlist/denylist` filter to set the `lqi`.
339 * @note The `RssIn` list contains Extended Addresses whose `lqi` or
340 * received signal strength (`rss`) values have been set to be different from the defaults.
341 * The `lqi` will automatically get converted to a corresponding `rss` value.
342 * @par
343 * This is available when `OPENTHREAD_CONFIG_MAC_FILTER_ENABLE` configuration is enabled.
344 * @sa otLinkConvertLinkQualityToRss
345 * @sa otLinkFilterSetDefaultRssIn
346 */
347 else if (aArgs[0] == "add-lqi")
348 {
349 uint8_t linkQuality;
350
351 SuccessOrExit(error = aArgs[2].ParseAsUint8(linkQuality));
352 VerifyOrExit(linkQuality <= 3, error = OT_ERROR_INVALID_ARGS);
353 rss = otLinkConvertLinkQualityToRss(GetInstancePtr(), linkQuality);
354
355 if (aArgs[1] == "*")
356 {
357 otLinkFilterSetDefaultRssIn(GetInstancePtr(), rss);
358 }
359 else
360 {
361 SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8));
362 error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss);
363 }
364 }
365 /**
366 * @cli macfilter rss add
367 * @code
368 * macfilter rss add * -50
369 * Done
370 * @endcode
371 * @code
372 * macfilter rss add 0f6127e33af6b404 -85
373 * Done
374 * @endcode
375 * @cparam macfilter rss add @ca{extaddr} @ca{rss}
376 * To set a default value for the received signal strength for all received messages,
377 * use the `*` for the `extaddr` argument.
378 * @par api_copy
379 * #otLinkFilterAddRssIn
380 */
381 else if (aArgs[0] == "add")
382 {
383 SuccessOrExit(error = aArgs[2].ParseAsInt8(rss));
384
385 if (aArgs[1] == "*")
386 {
387 otLinkFilterSetDefaultRssIn(GetInstancePtr(), rss);
388 }
389 else
390 {
391 SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8));
392 error = otLinkFilterAddRssIn(GetInstancePtr(), &extAddr, rss);
393 }
394 }
395 /**
396 * @cli macfilter rss remove
397 * @code
398 * macfilter rss remove *
399 * Done
400 * @endcode
401 * @code
402 * macfilter rss remove 0f6127e33af6b404
403 * Done
404 * @endcode
405 * @cparam macfilter rss remove @ca{extaddr}
406 * If you wish to remove the default received signal strength and link quality indicator settings,
407 * use the `*` as the `extaddr`. This unsets the defaults but does not remove
408 * entries from the `RssIn` list.
409 * @par api_copy
410 * #otLinkFilterRemoveRssIn
411 */
412 else if (aArgs[0] == "remove")
413 {
414 if (aArgs[1] == "*")
415 {
416 otLinkFilterClearDefaultRssIn(GetInstancePtr());
417 }
418 else
419 {
420 SuccessOrExit(error = aArgs[1].ParseAsHexString(extAddr.m8));
421 otLinkFilterRemoveRssIn(GetInstancePtr(), &extAddr);
422 }
423 }
424 /**
425 * @cli macfilter rss clear
426 * @code
427 * macfilter rss clear
428 * Done
429 * @endcode
430 * @par api_copy
431 * #otLinkFilterClearAllRssIn
432 */
433 else if (aArgs[0] == "clear")
434 {
435 otLinkFilterClearAllRssIn(GetInstancePtr());
436 }
437 else
438 {
439 error = OT_ERROR_INVALID_COMMAND;
440 }
441
442 exit:
443 return error;
444 }
445
Process(Arg aArgs[])446 otError MacFilter::Process(Arg aArgs[])
447 {
448 #define CmdEntry(aCommandString) \
449 { \
450 aCommandString, &MacFilter::Process<Cmd(aCommandString)> \
451 }
452
453 static constexpr Command kCommands[] = {
454 CmdEntry("addr"),
455 CmdEntry("rss"),
456 };
457
458 #undef CmdEntry
459
460 static_assert(BinarySearch::IsSorted(kCommands), "kCommands is not sorted");
461
462 otError error = OT_ERROR_INVALID_COMMAND;
463 const Command *command;
464
465 /**
466 * @cli macfilter
467 * @code
468 * macfilter
469 * Address Mode: Allowlist
470 * 0f6127e33af6b403 : rss -95 (lqi 1)
471 * 0f6127e33af6b402
472 * RssIn List:
473 * 0f6127e33af6b403 : rss -95 (lqi 1)
474 * Default rss: -50 (lqi 3)
475 * Done
476 * @endcode
477 * @par
478 * Provides the following information:
479 * - `Address Mode`: Current mode of the MAC filter: Either `AllowList`, `DenyList,` or `Disabled`
480 * - A list of all the extended addresses in the MAC filter list. The received signal strength (rss) and
481 * link quality indicator (lqi) are listed next to the address if these values have been set to be
482 * different from the default values.
483 * - A separate list (`RssIn List`) that shows all the extended addresses where the `rss` has been set to
484 * be different from the default value.
485 * - `Default rss`: Shows the default values, if applicable, for the `rss` and `lqi` settings.
486 * @note An extended address can be in the `RssIn` list without being in the MAC filter list.
487 * @sa otLinkFilterSetAddressMode
488 * @sa otLinkFilterGetNextAddress
489 * @sa otLinkFilterGetNextRssIn
490 */
491 if (aArgs[0].IsEmpty())
492 {
493 OutputFilter(kAddressFilter | kRssFilter);
494 ExitNow(error = OT_ERROR_NONE);
495 }
496
497 command = BinarySearch::Find(aArgs[0].GetCString(), kCommands);
498 VerifyOrExit(command != nullptr);
499
500 error = (this->*command->mHandler)(aArgs + 1);
501
502 exit:
503 return error;
504 }
505
506 } // namespace Cli
507 } // namespace ot
508
509 #endif // OPENTHREAD_CONFIG_MAC_FILTER_ENABLE
510