/src/openweave-core/src/inet/InetInterface.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2019 Google LLC. |
4 | | * Copyright (c) 2013-2017 Nest Labs, Inc. |
5 | | * All rights reserved. |
6 | | * |
7 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | | * you may not use this file except in compliance with the License. |
9 | | * You may obtain a copy of the License at |
10 | | * |
11 | | * http://www.apache.org/licenses/LICENSE-2.0 |
12 | | * |
13 | | * Unless required by applicable law or agreed to in writing, software |
14 | | * distributed under the License is distributed on an "AS IS" BASIS, |
15 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | | * See the License for the specific language governing permissions and |
17 | | * limitations under the License. |
18 | | */ |
19 | | |
20 | | /** |
21 | | * @file |
22 | | * Implementation of network interface abstraction layer. |
23 | | * |
24 | | */ |
25 | | |
26 | | #ifndef __STDC_LIMIT_MACROS |
27 | | #define __STDC_LIMIT_MACROS |
28 | | #endif |
29 | | |
30 | | #include <stdio.h> |
31 | | #include <string.h> |
32 | | |
33 | | #include <Weave/Support/CodeUtils.h> |
34 | | #include <Weave/Support/NLDLLUtil.h> |
35 | | |
36 | | #include <InetLayer/InetLayer.h> |
37 | | #include <InetLayer/InetLayerEvents.h> |
38 | | #include <InetLayer/IPPrefix.h> |
39 | | |
40 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
41 | | #include <lwip/tcpip.h> |
42 | | #include <lwip/sys.h> |
43 | | #include <lwip/netif.h> |
44 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
45 | | |
46 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
47 | | #include <errno.h> |
48 | | #include <unistd.h> |
49 | | #include <fcntl.h> |
50 | | #include <sys/socket.h> |
51 | | #ifdef HAVE_SYS_SOCKIO_H |
52 | | #include <sys/sockio.h> |
53 | | #endif /* HAVE_SYS_SOCKIO_H */ |
54 | | #include <sys/ioctl.h> |
55 | | #include <net/if.h> |
56 | | #ifdef __ANDROID__ |
57 | | #include "ifaddrs-android.h" |
58 | | #else // !defined(__ANDROID__) |
59 | | #include <ifaddrs.h> |
60 | | #endif // !defined(__ANDROID__) |
61 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
62 | | |
63 | | namespace nl { |
64 | | namespace Inet { |
65 | | |
66 | | |
67 | | /** |
68 | | * @brief Get the name of a network interface |
69 | | * |
70 | | * @param[in] intfId a network interface |
71 | | * @param[in] nameBuf region of memory to write the interface name |
72 | | * @param[in] nameBufSize size of the region denoted by \c nameBuf |
73 | | * |
74 | | * @retval INET_NO_ERROR successful result, interface name written |
75 | | * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer |
76 | | * @retval other another system or platform error |
77 | | * |
78 | | * @details |
79 | | * Writes the name of the network interface as \c NUL terminated text string |
80 | | * at \c nameBuf. The name of the unspecified network interface is the empty |
81 | | * string. |
82 | | */ |
83 | | NL_DLL_EXPORT INET_ERROR GetInterfaceName(InterfaceId intfId, char *nameBuf, size_t nameBufSize) |
84 | 0 | { |
85 | 0 | if (intfId != INET_NULL_INTERFACEID) |
86 | 0 | { |
87 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
88 | | int status = snprintf(nameBuf, nameBufSize, "%c%c%d", intfId->name[0], intfId->name[1], intfId->num); |
89 | | if (status >= static_cast<int>(nameBufSize)) |
90 | | return INET_ERROR_NO_MEMORY; |
91 | | return INET_NO_ERROR; |
92 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
93 | |
|
94 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
95 | 0 | char intfName[IF_NAMESIZE]; |
96 | 0 | if (if_indextoname(intfId, intfName) == NULL) |
97 | 0 | return Weave::System::MapErrorPOSIX(errno); |
98 | 0 | if (strlen(intfName) >= nameBufSize) |
99 | 0 | return INET_ERROR_NO_MEMORY; |
100 | 0 | strcpy(nameBuf, intfName); |
101 | 0 | return INET_NO_ERROR; |
102 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
103 | 0 | } |
104 | 0 | else |
105 | 0 | { |
106 | 0 | if (nameBufSize < 1) |
107 | 0 | return INET_ERROR_NO_MEMORY; |
108 | 0 | nameBuf[0] = 0; |
109 | 0 | return INET_NO_ERROR; |
110 | 0 | } |
111 | 0 | } |
112 | | |
113 | | /** |
114 | | * @brief Search the list of network interfaces for the indicated name. |
115 | | * |
116 | | * @param[in] intfName name of the network interface to find |
117 | | * @param[out] intfId indicator of the network interface to assign |
118 | | * |
119 | | * @retval INET_NO_ERROR success, network interface indicated |
120 | | * @retval INET_ERROR_UNKNOWN_INTERFACE no network interface found |
121 | | * @retval other another system or platform error |
122 | | * |
123 | | * @details |
124 | | * On LwIP, this function must be called with the LwIP stack lock acquired. |
125 | | * |
126 | | * The \c intfId parameter is not updated unless the value returned is |
127 | | * \c INET_NO_ERROR. It should be initialized with \c INET_NULL_INTERFACEID |
128 | | * before calling this function. |
129 | | */ |
130 | | NL_DLL_EXPORT INET_ERROR InterfaceNameToId(const char *intfName, InterfaceId& intfId) |
131 | 0 | { |
132 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
133 | | if (strlen(intfName) < 3) |
134 | | return INET_ERROR_UNKNOWN_INTERFACE; |
135 | | char *parseEnd; |
136 | | unsigned long intfNum = strtoul(intfName + 2, &parseEnd, 10); |
137 | | if (*parseEnd != 0 || intfNum > UINT8_MAX) |
138 | | return INET_ERROR_UNKNOWN_INTERFACE; |
139 | | struct netif * intf; |
140 | | #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) |
141 | | NETIF_FOREACH(intf) |
142 | | #else |
143 | | for (intf = netif_list; intf != NULL; intf = intf->next) |
144 | | #endif |
145 | | { |
146 | | if (intf->name[0] == intfName[0] && intf->name[1] == intfName[1] && intf->num == (uint8_t)intfNum) |
147 | | { |
148 | | intfId = intf; |
149 | | return INET_NO_ERROR; |
150 | | } |
151 | | } |
152 | | intfId = INET_NULL_INTERFACEID; |
153 | | return INET_ERROR_UNKNOWN_INTERFACE; |
154 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
155 | |
|
156 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
157 | 0 | intfId = if_nametoindex(intfName); |
158 | 0 | if (intfId == 0) |
159 | 0 | return (errno == ENXIO) ? INET_ERROR_UNKNOWN_INTERFACE : Weave::System::MapErrorPOSIX(errno); |
160 | 0 | return INET_NO_ERROR; |
161 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
162 | 0 | } |
163 | | |
164 | | |
165 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
166 | | |
167 | | static int sIOCTLSocket = -1; |
168 | | |
169 | | /** |
170 | | * @brief Returns a global general purpose socket useful for invoking certain network IOCTLs. |
171 | | * |
172 | | * This function is thread-safe on all platforms. |
173 | | */ |
174 | | int GetIOCTLSocket(void) |
175 | 0 | { |
176 | 0 | if (sIOCTLSocket == -1) |
177 | 0 | { |
178 | 0 | int s; |
179 | 0 | #ifdef SOCK_CLOEXEC |
180 | 0 | s = socket(AF_INET, SOCK_STREAM, SOCK_CLOEXEC); |
181 | 0 | if (s < 0) |
182 | 0 | #endif |
183 | 0 | { |
184 | 0 | s = socket(AF_INET, SOCK_STREAM, 0); |
185 | 0 | fcntl(s, O_CLOEXEC); |
186 | 0 | } |
187 | |
|
188 | 0 | if (!__sync_bool_compare_and_swap(&sIOCTLSocket, -1, s)) |
189 | 0 | { |
190 | 0 | close(s); |
191 | 0 | } |
192 | 0 | } |
193 | 0 | return sIOCTLSocket; |
194 | 0 | } |
195 | | |
196 | | /** |
197 | | * @brief Close the global socket created by \c GetIOCTLSocket. |
198 | | * |
199 | | * @details |
200 | | * This function is provided for cases were leaving the global IOCTL socket |
201 | | * open would register as a leak. |
202 | | * |
203 | | * NB: This function is NOT thread-safe with respect to \c GetIOCTLSocket. |
204 | | */ |
205 | | void CloseIOCTLSocket(void) |
206 | 0 | { |
207 | 0 | if (sIOCTLSocket == -1) |
208 | 0 | { |
209 | 0 | close(sIOCTLSocket); |
210 | 0 | sIOCTLSocket = -1; |
211 | 0 | } |
212 | 0 | } |
213 | | |
214 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
215 | | |
216 | | |
217 | | /** |
218 | | * @fn InterfaceIterator::InterfaceIterator(void) |
219 | | * |
220 | | * @brief Constructs an InterfaceIterator object. |
221 | | * |
222 | | * @details |
223 | | * Starts the iterator at the first network interface. On some platforms, |
224 | | * this constructor may allocate resources recycled by the destructor. |
225 | | */ |
226 | | |
227 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
228 | | |
229 | | #if __ANDROID__ && __ANDROID_API__ < 24 |
230 | | |
231 | | static struct if_nameindex * backport_if_nameindex(void); |
232 | | static void backport_if_freenameindex(struct if_nameindex *); |
233 | | |
234 | | static void backport_if_freenameindex(struct if_nameindex * inArray) |
235 | | { |
236 | | if (inArray == NULL) |
237 | | return; |
238 | | |
239 | | for (size_t i = 0; inArray[i].if_index != 0; i++) |
240 | | { |
241 | | if (inArray[i].if_name != NULL) |
242 | | free(inArray[i].if_name); |
243 | | } |
244 | | |
245 | | free(inArray); |
246 | | } |
247 | | |
248 | | static struct if_nameindex * backport_if_nameindex(void) |
249 | | { |
250 | | int err; |
251 | | unsigned index; |
252 | | size_t intfIter = 0; |
253 | | size_t maxIntfNum = 0; |
254 | | size_t numIntf = 0; |
255 | | size_t numAddrs = 0; |
256 | | struct if_nameindex * retval = NULL; |
257 | | struct if_nameindex * tmpval = NULL; |
258 | | struct ifaddrs * addrList = NULL; |
259 | | struct ifaddrs * addrIter = NULL; |
260 | | const char * lastIntfName = ""; |
261 | | |
262 | | err = getifaddrs(&addrList); |
263 | | VerifyOrExit(err >= 0, ); |
264 | | |
265 | | // coalesce on consecutive interface names |
266 | | for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next) |
267 | | { |
268 | | numAddrs++; |
269 | | if (strcmp(addrIter->ifa_name, lastIntfName) == 0) |
270 | | continue; |
271 | | numIntf++; |
272 | | lastIntfName = addrIter->ifa_name; |
273 | | } |
274 | | |
275 | | tmpval = (struct if_nameindex *) malloc((numIntf + 1) * sizeof(struct if_nameindex)); |
276 | | VerifyOrExit(tmpval != NULL, ); |
277 | | memset(tmpval, 0, (numIntf + 1) * sizeof(struct if_nameindex)); |
278 | | |
279 | | lastIntfName = ""; |
280 | | for (addrIter = addrList; addrIter != NULL; addrIter = addrIter->ifa_next) |
281 | | { |
282 | | if (strcmp(addrIter->ifa_name, lastIntfName) == 0) |
283 | | continue; |
284 | | |
285 | | index = if_nametoindex(addrIter->ifa_name); |
286 | | if (index != 0) |
287 | | { |
288 | | tmpval[intfIter].if_index = index; |
289 | | tmpval[intfIter].if_name = strdup(addrIter->ifa_name); |
290 | | intfIter++; |
291 | | } |
292 | | lastIntfName = addrIter->ifa_name; |
293 | | } |
294 | | |
295 | | // coalesce on interface index |
296 | | maxIntfNum = 0; |
297 | | for (size_t i = 0; tmpval[i].if_index != 0; i++) |
298 | | { |
299 | | if (maxIntfNum < tmpval[i].if_index) |
300 | | maxIntfNum = tmpval[i].if_index; |
301 | | } |
302 | | |
303 | | retval = (struct if_nameindex *) malloc((maxIntfNum + 1) * sizeof(struct if_nameindex)); |
304 | | VerifyOrExit(retval != NULL, ); |
305 | | memset(retval, 0, (maxIntfNum + 1) * sizeof(struct if_nameindex)); |
306 | | |
307 | | for (size_t i = 0; tmpval[i].if_index != 0; i++) |
308 | | { |
309 | | struct if_nameindex * intf = &tmpval[i]; |
310 | | if (retval[intf->if_index - 1].if_index == 0) |
311 | | { |
312 | | retval[intf->if_index - 1] = *intf; |
313 | | } |
314 | | else |
315 | | { |
316 | | free(intf->if_name); |
317 | | intf->if_index = 0; |
318 | | intf->if_name = 0; |
319 | | } |
320 | | } |
321 | | |
322 | | intfIter = 0; |
323 | | |
324 | | // coalesce potential gaps between indeces |
325 | | for (size_t i = 0; i < maxIntfNum; i++) |
326 | | { |
327 | | if (retval[i].if_index != 0) |
328 | | { |
329 | | retval[intfIter] = retval[i]; |
330 | | intfIter++; |
331 | | } |
332 | | } |
333 | | |
334 | | for (size_t i = intfIter; i < maxIntfNum; i++) |
335 | | { |
336 | | retval[i].if_index = 0; |
337 | | retval[i].if_name = NULL; |
338 | | } |
339 | | |
340 | | exit: |
341 | | if (tmpval != NULL) |
342 | | { |
343 | | free(tmpval); |
344 | | } |
345 | | |
346 | | if (addrList != NULL) |
347 | | { |
348 | | freeifaddrs(addrList); |
349 | | } |
350 | | |
351 | | return retval; |
352 | | } |
353 | | |
354 | | #endif // __ANDROID__ && __ANDROID_API__ < 24 |
355 | | |
356 | | InterfaceIterator::InterfaceIterator(void) |
357 | 0 | { |
358 | 0 | mIntfArray = NULL; |
359 | 0 | mCurIntf = 0; |
360 | 0 | mIntfFlags = 0; |
361 | 0 | mIntfFlagsCached = 0; |
362 | 0 | } |
363 | | |
364 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
365 | | |
366 | | /** |
367 | | * @fn InterfaceIterator::~InterfaceIterator(void) |
368 | | * |
369 | | * @brief Destroys an InterfaceIterator object. |
370 | | * |
371 | | * @details |
372 | | * Recycles any resources allocated by the constructor. |
373 | | */ |
374 | | |
375 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
376 | | |
377 | | InterfaceIterator::~InterfaceIterator(void) |
378 | 0 | { |
379 | 0 | if (mIntfArray != NULL) |
380 | 0 | { |
381 | | #if __ANDROID__ && __ANDROID_API__ < 24 |
382 | | backport_if_freenameindex(mIntfArray); |
383 | | #else |
384 | 0 | if_freenameindex(mIntfArray); |
385 | 0 | #endif |
386 | 0 | mIntfArray = NULL; |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
391 | | |
392 | | /** |
393 | | * @fn bool InterfaceIterator::HasCurrent(void) |
394 | | * |
395 | | * @brief Test whether the iterator is positioned on an interface |
396 | | * |
397 | | * @return \c true if the iterator is positioned on an interface; |
398 | | * \c false if positioned beyond the end of the interface list. |
399 | | */ |
400 | | |
401 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
402 | | |
403 | | bool InterfaceIterator::HasCurrent(void) |
404 | 0 | { |
405 | 0 | return (mIntfArray != NULL) |
406 | 0 | ? mIntfArray[mCurIntf].if_index != 0 |
407 | 0 | : Next(); |
408 | 0 | } |
409 | | |
410 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
411 | | |
412 | | /** |
413 | | * @fn bool InterfaceIterator::Next(void) |
414 | | * |
415 | | * @brief Advance the iterator to the next network interface. |
416 | | * |
417 | | * @return \c false if advanced beyond the end, else \c true. |
418 | | * |
419 | | * @details |
420 | | * Advances the internal iterator to the next network interface or to a position |
421 | | * beyond the end of the interface list. |
422 | | * |
423 | | * On multi-threaded LwIP systems, this method is thread-safe relative to other |
424 | | * threads accessing the global LwIP state provided that: 1) the other threads |
425 | | * hold the LwIP core lock while mutating the list of netifs; and 2) netif objects |
426 | | * themselves are never destroyed. |
427 | | * |
428 | | * Iteration is stable in the face of changes to the underlying system's |
429 | | * interfaces, *except* in the case of LwIP systems when the currently selected |
430 | | * interface is removed from the list, which causes iteration to end immediately. |
431 | | */ |
432 | | bool InterfaceIterator::Next(void) |
433 | 0 | { |
434 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
435 | |
|
436 | 0 | if (mIntfArray == NULL) |
437 | 0 | { |
438 | | #if __ANDROID__ && __ANDROID_API__ < 24 |
439 | | mIntfArray = backport_if_nameindex(); |
440 | | #else |
441 | 0 | mIntfArray = if_nameindex(); |
442 | 0 | #endif |
443 | 0 | } |
444 | 0 | else if (mIntfArray[mCurIntf].if_index != 0) |
445 | 0 | { |
446 | 0 | mCurIntf++; |
447 | 0 | mIntfFlags = 0; |
448 | 0 | mIntfFlagsCached = false; |
449 | 0 | } |
450 | 0 | return (mIntfArray != NULL && mIntfArray[mCurIntf].if_index != 0); |
451 | |
|
452 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
453 | |
|
454 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
455 | | |
456 | | // Lock LwIP stack |
457 | | LOCK_TCPIP_CORE(); |
458 | | |
459 | | // Verify the previous netif is still on the list if netifs. If so, |
460 | | // advance to the next nextif. |
461 | | struct netif * prevNetif = mCurNetif; |
462 | | #if LWIP_VERSION_MAJOR >= 2 && LWIP_VERSION_MINOR >= 0 && defined(NETIF_FOREACH) |
463 | | NETIF_FOREACH(mCurNetif) |
464 | | #else |
465 | | for (mCurNetif = netif_list; mCurNetif != NULL; mCurNetif = mCurNetif->next) |
466 | | #endif |
467 | | { |
468 | | if (mCurNetif == prevNetif) |
469 | | { |
470 | | mCurNetif = mCurNetif->next; |
471 | | break; |
472 | | } |
473 | | } |
474 | | |
475 | | // Unlock LwIP stack |
476 | | UNLOCK_TCPIP_CORE(); |
477 | | |
478 | | return mCurNetif != NULL; |
479 | | |
480 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
481 | 0 | } |
482 | | |
483 | | /** |
484 | | * @fn InterfaceId InterfaceIterator::GetInterfaceId(void) |
485 | | * |
486 | | * @brief Returns the network interface id at the current iterator position. |
487 | | * |
488 | | * @retval INET_NULL_INTERFACEID if advanced beyond the end of the list. |
489 | | * @retval id the current network interface id. |
490 | | */ |
491 | | |
492 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
493 | | |
494 | | InterfaceId InterfaceIterator::GetInterfaceId(void) |
495 | 0 | { |
496 | 0 | return (HasCurrent()) |
497 | 0 | ? mIntfArray[mCurIntf].if_index |
498 | 0 | : INET_NULL_INTERFACEID; |
499 | 0 | } |
500 | | |
501 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
502 | | |
503 | | |
504 | | /** |
505 | | * @brief Get the name of the current network interface |
506 | | * |
507 | | * @param[in] nameBuf region of memory to write the interface name |
508 | | * @param[in] nameBufSize size of the region denoted by \c nameBuf |
509 | | * |
510 | | * @retval INET_NO_ERROR successful result, interface name written |
511 | | * @retval INET_ERROR_INCORRECT_STATE |
512 | | * iterator is positioned beyond the end of |
513 | | * the list |
514 | | * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer |
515 | | * @retval other another system or platform error |
516 | | * |
517 | | * @details |
518 | | * Writes the name of the network interface as \c NUL terminated text string |
519 | | * at \c nameBuf. |
520 | | */ |
521 | | INET_ERROR InterfaceIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize) |
522 | 0 | { |
523 | 0 | INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED; |
524 | |
|
525 | 0 | VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE); |
526 | | |
527 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
528 | 0 | VerifyOrExit(strlen(mIntfArray[mCurIntf].if_name) < nameBufSize, err = INET_ERROR_NO_MEMORY); |
529 | 0 | strncpy(nameBuf, mIntfArray[mCurIntf].if_name, nameBufSize); |
530 | 0 | err = INET_NO_ERROR; |
531 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
532 | |
|
533 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
534 | | err = ::nl::Inet::GetInterfaceName(mCurNetif, nameBuf, nameBufSize); |
535 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
536 | |
|
537 | 0 | exit: |
538 | 0 | return err; |
539 | 0 | } |
540 | | |
541 | | /** |
542 | | * @brief Returns whether the current network interface is up. |
543 | | * |
544 | | * @return \c true if current network interface is up, \c false if not |
545 | | * or if the iterator is positioned beyond the end of the list. |
546 | | */ |
547 | | bool InterfaceIterator::IsUp(void) |
548 | 0 | { |
549 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
550 | 0 | return (GetFlags() & IFF_UP) != 0; |
551 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
552 | |
|
553 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
554 | | return HasCurrent() && netif_is_up(mCurNetif); |
555 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
556 | 0 | } |
557 | | |
558 | | /** |
559 | | * @brief Returns whether the current network interface supports multicast. |
560 | | * |
561 | | * @return \c true if current network interface supports multicast, \c false |
562 | | * if not, or if the iterator is positioned beyond the end of the list. |
563 | | */ |
564 | | bool InterfaceIterator::SupportsMulticast(void) |
565 | 0 | { |
566 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
567 | 0 | return (GetFlags() & IFF_MULTICAST) != 0; |
568 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
569 | |
|
570 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
571 | | return HasCurrent() && |
572 | | #if LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
573 | | (mCurNetif->flags & (NETIF_FLAG_IGMP | NETIF_FLAG_MLD6 | NETIF_FLAG_BROADCAST)) != 0; |
574 | | #else |
575 | | (mCurNetif->flags & NETIF_FLAG_POINTTOPOINT) == 0; |
576 | | #endif // LWIP_VERSION_MAJOR > 1 || LWIP_VERSION_MINOR >= 5 |
577 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
578 | 0 | } |
579 | | |
580 | | /** |
581 | | * @brief Returns whether the current network interface has a broadcast address. |
582 | | * |
583 | | * @return \c true if current network interface has a broadcast address, \c false |
584 | | * if not, or if the iterator is positioned beyond the end of the list. |
585 | | */ |
586 | | bool InterfaceIterator::HasBroadcastAddress(void) |
587 | 0 | { |
588 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
589 | 0 | return (GetFlags() & IFF_BROADCAST) != 0; |
590 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
591 | |
|
592 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
593 | | return HasCurrent() && (mCurNetif->flags & NETIF_FLAG_BROADCAST) != 0; |
594 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
595 | 0 | } |
596 | | |
597 | | /** |
598 | | * @fn short InterfaceIterator::GetFlags(void) |
599 | | * |
600 | | * @brief Returns the ifr_flags value for the current interface. |
601 | | */ |
602 | | |
603 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
604 | | |
605 | | short InterfaceIterator::GetFlags(void) |
606 | 0 | { |
607 | 0 | struct ifreq intfData; |
608 | |
|
609 | 0 | if (!mIntfFlagsCached && HasCurrent()) |
610 | 0 | { |
611 | 0 | strncpy(intfData.ifr_name, mIntfArray[mCurIntf].if_name, IFNAMSIZ); |
612 | 0 | intfData.ifr_name[IFNAMSIZ-1] = '\0'; |
613 | |
|
614 | 0 | int res = ioctl(GetIOCTLSocket(), SIOCGIFFLAGS, &intfData); |
615 | 0 | if (res == 0) |
616 | 0 | { |
617 | 0 | mIntfFlags = intfData.ifr_flags; |
618 | 0 | mIntfFlagsCached = true; |
619 | 0 | } |
620 | 0 | } |
621 | |
|
622 | 0 | return mIntfFlags; |
623 | 0 | } |
624 | | |
625 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
626 | | |
627 | | /** |
628 | | * @fn InterfaceAddressIterator::InterfaceAddressIterator(void) |
629 | | * |
630 | | * @brief Constructs an InterfaceAddressIterator object. |
631 | | * |
632 | | * @details |
633 | | * Starts the iterator at the first network address. On some platforms, |
634 | | * this constructor may allocate resources recycled by the destructor. |
635 | | */ |
636 | | |
637 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
638 | | |
639 | | InterfaceAddressIterator::InterfaceAddressIterator(void) |
640 | 0 | { |
641 | 0 | mAddrsList = NULL; |
642 | 0 | mCurAddr = NULL; |
643 | 0 | } |
644 | | |
645 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
646 | | |
647 | | |
648 | | /** |
649 | | * @fn InterfaceAddressIterator::~InterfaceAddressIterator(void) |
650 | | * |
651 | | * @brief Destroys an InterfaceAddressIterator object. |
652 | | * |
653 | | * @details |
654 | | * Recycles any resources allocated by the constructor. |
655 | | */ |
656 | | |
657 | | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
658 | | |
659 | | InterfaceAddressIterator::~InterfaceAddressIterator(void) |
660 | 0 | { |
661 | 0 | if (mAddrsList != NULL) |
662 | 0 | { |
663 | 0 | freeifaddrs(mAddrsList); |
664 | 0 | mAddrsList = mCurAddr = NULL; |
665 | 0 | } |
666 | 0 | } |
667 | | |
668 | | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
669 | | |
670 | | /** |
671 | | * @fn bool InterfaceIterator::HasCurrent(void) |
672 | | * |
673 | | * @brief Test whether the iterator is positioned on an interface address |
674 | | * |
675 | | * @return \c true if the iterator is positioned on an interface address; |
676 | | * \c false if positioned beyond the end of the address list. |
677 | | */ |
678 | | bool InterfaceAddressIterator::HasCurrent(void) |
679 | 0 | { |
680 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
681 | |
|
682 | 0 | return (mAddrsList != NULL) ? (mCurAddr != NULL) : Next(); |
683 | |
|
684 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
685 | |
|
686 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
687 | | |
688 | | return mIntfIter.HasCurrent() && ((mCurAddrIndex != kBeforeStartIndex) || Next()); |
689 | | |
690 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
691 | 0 | } |
692 | | |
693 | | /** |
694 | | * @fn bool InterfaceAddressIterator::Next(void) |
695 | | * |
696 | | * @brief Advance the iterator to the next interface address. |
697 | | * |
698 | | * @return \c false if advanced beyond the end, else \c true. |
699 | | * |
700 | | * @details |
701 | | * Advances the iterator to the next interface address or to a position |
702 | | * beyond the end of the address list. |
703 | | * |
704 | | * On LwIP, this method is thread-safe provided that: 1) other threads hold |
705 | | * the LwIP core lock while mutating the netif list; and 2) netif objects |
706 | | * themselves are never destroyed. Additionally, iteration on LwIP systems |
707 | | * will terminate early if the current interface is removed from the list. |
708 | | */ |
709 | | bool InterfaceAddressIterator::Next(void) |
710 | 0 | { |
711 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
712 | |
|
713 | 0 | while (true) |
714 | 0 | { |
715 | 0 | if (mAddrsList == NULL) |
716 | 0 | { |
717 | 0 | int res = getifaddrs(&mAddrsList); |
718 | 0 | if (res < 0) |
719 | 0 | { |
720 | 0 | return false; |
721 | 0 | } |
722 | 0 | mCurAddr = mAddrsList; |
723 | 0 | } |
724 | 0 | else if (mCurAddr != NULL) |
725 | 0 | { |
726 | 0 | mCurAddr = mCurAddr->ifa_next; |
727 | 0 | } |
728 | | |
729 | 0 | if (mCurAddr == NULL) |
730 | 0 | { |
731 | 0 | return false; |
732 | 0 | } |
733 | | |
734 | 0 | if (mCurAddr->ifa_addr != NULL && |
735 | 0 | (mCurAddr->ifa_addr->sa_family == AF_INET6 |
736 | 0 | #if INET_CONFIG_ENABLE_IPV4 |
737 | 0 | || mCurAddr->ifa_addr->sa_family == AF_INET |
738 | 0 | #endif // INET_CONFIG_ENABLE_IPV4 |
739 | 0 | )) |
740 | 0 | { |
741 | 0 | return true; |
742 | 0 | } |
743 | 0 | } |
744 | |
|
745 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
746 | |
|
747 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
748 | | |
749 | | mCurAddrIndex++; |
750 | | |
751 | | while (mIntfIter.HasCurrent()) |
752 | | { |
753 | | struct netif * curIntf = mIntfIter.GetInterfaceId(); |
754 | | |
755 | | while (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES) |
756 | | { |
757 | | if (ip6_addr_isvalid(netif_ip6_addr_state(curIntf, mCurAddrIndex))) |
758 | | { |
759 | | return true; |
760 | | } |
761 | | mCurAddrIndex++; |
762 | | } |
763 | | |
764 | | #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
765 | | if (mCurAddrIndex == LWIP_IPV6_NUM_ADDRESSES) |
766 | | { |
767 | | if (!ip4_addr_isany(netif_ip4_addr(curIntf))) |
768 | | { |
769 | | return true; |
770 | | } |
771 | | } |
772 | | #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
773 | | |
774 | | mIntfIter.Next(); |
775 | | mCurAddrIndex = 0; |
776 | | } |
777 | | |
778 | | return false; |
779 | | |
780 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
781 | 0 | } |
782 | | |
783 | | /** |
784 | | * @fn IPAddress InterfaceAddressIterator::GetAddress(void) |
785 | | * |
786 | | * @brief Get the current interface address. |
787 | | * |
788 | | * @return the current interface address or \c IPAddress::Any if the iterator |
789 | | * is positioned beyond the end of the address list. |
790 | | */ |
791 | | IPAddress InterfaceAddressIterator::GetAddress(void) |
792 | 0 | { |
793 | 0 | if (HasCurrent()) |
794 | 0 | { |
795 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
796 | 0 | return IPAddress::FromSockAddr(*mCurAddr->ifa_addr); |
797 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
798 | |
|
799 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
800 | | struct netif * curIntf = mIntfIter.GetInterfaceId(); |
801 | | |
802 | | if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES) |
803 | | { |
804 | | return IPAddress::FromIPv6(*netif_ip6_addr(curIntf, mCurAddrIndex)); |
805 | | } |
806 | | #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
807 | | else |
808 | | { |
809 | | return IPAddress::FromIPv4(*netif_ip4_addr(curIntf)); |
810 | | } |
811 | | #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
812 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
813 | 0 | } |
814 | | |
815 | 0 | return IPAddress::Any; |
816 | 0 | } |
817 | | |
818 | | /** |
819 | | * @fn uint8_t InterfaceAddressIterator::GetPrefixLength(void) |
820 | | * |
821 | | * @brief Gets the network prefix associated with the current interface address. |
822 | | * |
823 | | * @return the network prefix (in bits) or 0 if the iterator is positioned beyond |
824 | | * the end of the address list. |
825 | | * |
826 | | * @details |
827 | | * On LwIP, this method simply returns the hard-coded constant 64. |
828 | | * |
829 | | * Note Well: the standard subnet prefix on all links other than PPP |
830 | | * links is 64 bits. On PPP links and some non-broadcast multipoint access |
831 | | * links, the convention is either 127 bits or 128 bits, but it might be |
832 | | * something else. On most platforms, the system's interface address |
833 | | * structure can represent arbitrary prefix lengths between 0 and 128. |
834 | | */ |
835 | | uint8_t InterfaceAddressIterator::GetPrefixLength(void) |
836 | 0 | { |
837 | 0 | if (HasCurrent()) |
838 | 0 | { |
839 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
840 | 0 | if (mCurAddr->ifa_addr->sa_family == AF_INET6) |
841 | 0 | { |
842 | 0 | struct sockaddr_in6& netmask = *(struct sockaddr_in6 *)(mCurAddr->ifa_netmask); |
843 | 0 | return NetmaskToPrefixLength(netmask.sin6_addr.s6_addr, 16); |
844 | 0 | } |
845 | 0 | if (mCurAddr->ifa_addr->sa_family == AF_INET) |
846 | 0 | { |
847 | 0 | struct sockaddr_in& netmask = *(struct sockaddr_in *)(mCurAddr->ifa_netmask); |
848 | 0 | return NetmaskToPrefixLength((const uint8_t *)&netmask.sin_addr.s_addr, 4); |
849 | 0 | } |
850 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
851 | |
|
852 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
853 | | if (mCurAddrIndex < LWIP_IPV6_NUM_ADDRESSES) |
854 | | { |
855 | | return 64; |
856 | | } |
857 | | #if INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
858 | | else |
859 | | { |
860 | | struct netif * curIntf = mIntfIter.GetInterfaceId(); |
861 | | return NetmaskToPrefixLength((const uint8_t *)netif_ip4_netmask(curIntf), 4); |
862 | | } |
863 | | #endif // INET_CONFIG_ENABLE_IPV4 && LWIP_IPV4 |
864 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
865 | 0 | } |
866 | 0 | return 0; |
867 | 0 | } |
868 | | |
869 | | /** |
870 | | * @fn InterfaceId InterfaceAddressIterator::GetInterfaceId(void) |
871 | | * |
872 | | * @brief Returns the network interface id associated with the current |
873 | | * interface address. |
874 | | * |
875 | | * @return the interface id or \c INET_NULL_INTERFACEID if the iterator |
876 | | * is positioned beyond the end of the address list. |
877 | | */ |
878 | | InterfaceId InterfaceAddressIterator::GetInterfaceId(void) |
879 | 0 | { |
880 | 0 | if (HasCurrent()) |
881 | 0 | { |
882 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
883 | 0 | return if_nametoindex(mCurAddr->ifa_name); |
884 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
885 | |
|
886 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
887 | | return mIntfIter.GetInterfaceId(); |
888 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
889 | 0 | } |
890 | 0 | return INET_NULL_INTERFACEID; |
891 | 0 | } |
892 | | |
893 | | /** |
894 | | * @fn INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize) |
895 | | * |
896 | | * @brief Get the name of the network interface associated with the |
897 | | * current interface address. |
898 | | * |
899 | | * @param[in] nameBuf region of memory to write the interface name |
900 | | * @param[in] nameBufSize size of the region denoted by \c nameBuf |
901 | | * |
902 | | * @retval INET_NO_ERROR successful result, interface name written |
903 | | * @retval INET_ERROR_NO_MEMORY name is too large to be written in buffer |
904 | | * @retval INET_ERROR_INCORRECT_STATE |
905 | | * the iterator is not currently positioned on an |
906 | | * interface address |
907 | | * @retval other another system or platform error |
908 | | * |
909 | | * @details |
910 | | * Writes the name of the network interface as \c NUL terminated text string |
911 | | * at \c nameBuf. |
912 | | */ |
913 | | INET_ERROR InterfaceAddressIterator::GetInterfaceName(char * nameBuf, size_t nameBufSize) |
914 | 0 | { |
915 | 0 | INET_ERROR err = INET_ERROR_NOT_IMPLEMENTED; |
916 | |
|
917 | 0 | VerifyOrExit(HasCurrent(), err = INET_ERROR_INCORRECT_STATE); |
918 | | |
919 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
920 | 0 | VerifyOrExit(strlen(mCurAddr->ifa_name) < nameBufSize, err = INET_ERROR_NO_MEMORY); |
921 | 0 | strncpy(nameBuf, mCurAddr->ifa_name, nameBufSize); |
922 | 0 | err = INET_NO_ERROR; |
923 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
924 | |
|
925 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
926 | | err = mIntfIter.GetInterfaceName(nameBuf, nameBufSize); |
927 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
928 | |
|
929 | 0 | exit: |
930 | 0 | return err; |
931 | 0 | } |
932 | | |
933 | | /** |
934 | | * @fn bool InterfaceAddressIterator::IsUp(void) |
935 | | * |
936 | | * @brief Returns whether the network interface associated with the current |
937 | | * interface address is up. |
938 | | * |
939 | | * @return \c true if current network interface is up, \c false if not, or |
940 | | * if the iterator is not positioned on an interface address. |
941 | | */ |
942 | | bool InterfaceAddressIterator::IsUp(void) |
943 | 0 | { |
944 | 0 | if (HasCurrent()) |
945 | 0 | { |
946 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
947 | 0 | return (mCurAddr->ifa_flags & IFF_UP) != 0; |
948 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
949 | |
|
950 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
951 | | return mIntfIter.IsUp(); |
952 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
953 | 0 | } |
954 | 0 | return false; |
955 | 0 | } |
956 | | |
957 | | /** |
958 | | * @fn bool InterfaceAddressIterator::SupportsMulticast(void) |
959 | | * |
960 | | * @brief Returns whether the network interface associated with the current |
961 | | * interface address supports multicast. |
962 | | * |
963 | | * @return \c true if multicast is supported, \c false if not, or |
964 | | * if the iterator is not positioned on an interface address. |
965 | | */ |
966 | | bool InterfaceAddressIterator::SupportsMulticast(void) |
967 | 0 | { |
968 | 0 | if (HasCurrent()) |
969 | 0 | { |
970 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
971 | 0 | return (mCurAddr->ifa_flags & IFF_MULTICAST) != 0; |
972 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
973 | |
|
974 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
975 | | return mIntfIter.SupportsMulticast(); |
976 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
977 | 0 | } |
978 | 0 | return false; |
979 | 0 | } |
980 | | |
981 | | /** |
982 | | * @fn bool InterfaceAddressIterator::HasBroadcastAddress(void) |
983 | | * |
984 | | * @brief Returns whether the network interface associated with the current |
985 | | * interface address has an IPv4 broadcast address. |
986 | | * |
987 | | * @return \c true if the interface has a broadcast address, \c false if not, or |
988 | | * if the iterator is not positioned on an interface address. |
989 | | */ |
990 | | bool InterfaceAddressIterator::HasBroadcastAddress(void) |
991 | 0 | { |
992 | 0 | if (HasCurrent()) |
993 | 0 | { |
994 | 0 | #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
995 | 0 | return (mCurAddr->ifa_flags & IFF_BROADCAST) != 0; |
996 | 0 | #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS |
997 | |
|
998 | | #if WEAVE_SYSTEM_CONFIG_USE_LWIP |
999 | | return mIntfIter.HasBroadcastAddress(); |
1000 | | #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP |
1001 | 0 | } |
1002 | 0 | return false; |
1003 | 0 | } |
1004 | | |
1005 | | /** |
1006 | | * @fn void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix) |
1007 | | * |
1008 | | * @brief Returns an IPPrefix containing the address and prefix length |
1009 | | * for the current address. |
1010 | | */ |
1011 | | void InterfaceAddressIterator::GetAddressWithPrefix(IPPrefix & addrWithPrefix) |
1012 | 0 | { |
1013 | 0 | if (HasCurrent()) |
1014 | 0 | { |
1015 | 0 | addrWithPrefix.IPAddr = GetAddress(); |
1016 | 0 | addrWithPrefix.Length = GetPrefixLength(); |
1017 | 0 | } |
1018 | 0 | else |
1019 | 0 | { |
1020 | 0 | addrWithPrefix = IPPrefix::Zero; |
1021 | 0 | } |
1022 | 0 | } |
1023 | | |
1024 | | /** |
1025 | | * @fn uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen) |
1026 | | * |
1027 | | * @brief Compute a prefix length from a variable-length netmask. |
1028 | | */ |
1029 | | uint8_t NetmaskToPrefixLength(const uint8_t * netmask, uint16_t netmaskLen) |
1030 | 0 | { |
1031 | 0 | uint8_t prefixLen = 0; |
1032 | |
|
1033 | 0 | for (uint8_t i = 0; i < netmaskLen; i++, prefixLen += 8) |
1034 | 0 | { |
1035 | 0 | uint8_t b = netmask[i]; |
1036 | 0 | if (b != 0xFF) |
1037 | 0 | { |
1038 | 0 | if ((b & 0xF0) == 0xF0) |
1039 | 0 | prefixLen += 4; |
1040 | 0 | else |
1041 | 0 | b = b >> 4; |
1042 | |
|
1043 | 0 | if ((b & 0x0C) == 0x0C) |
1044 | 0 | prefixLen += 2; |
1045 | 0 | else |
1046 | 0 | b = b >> 2; |
1047 | |
|
1048 | 0 | if ((b & 0x02) == 0x02) |
1049 | 0 | prefixLen++; |
1050 | |
|
1051 | 0 | break; |
1052 | 0 | } |
1053 | 0 | } |
1054 | |
|
1055 | 0 | return prefixLen; |
1056 | 0 | } |
1057 | | |
1058 | | } // namespace Inet |
1059 | | } // namespace nl |