1 /*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "lwip/opt.h"
32
33 #if LWIP_IFADDRS
34 #if (LWIP_IPV4 || LWIP_IPV6) && LWIP_SOCKET
35 #include "ifaddrs.h"
36
37 #include <stdlib.h>
38
39 #include "lwip/sys.h"
40 #include "lwip/tcpip.h"
41 #include "lwip/priv/sockets_priv.h"
42 #include "lwip/mem.h"
43 #include "lwip/netif.h"
44 #include "lwip/dhcp.h"
45
46 struct ifaddrs_storage {
47 struct ifaddrs ifa;
48 union {
49 struct sockaddr sa;
50 struct sockaddr_in s4;
51 #if LWIP_IPV6
52 struct sockaddr_in6 s6;
53 #endif
54 } addr, netmask, dstaddr;
55 char name[IFNAMSIZ];
56 };
57
58 struct getifaddrs_arg {
59 struct ifaddrs **ifap;
60 sys_sem_t cb_completed;
61 int ret;
62 };
63
64 static int tcpip_init_finish = 1;
65 void lwip_freeifaddrs(struct ifaddrs *ifa);
ifaddrs_add_tail(struct ifaddrs ** ifap,struct ifaddrs * ifaddr)66 static void ifaddrs_add_tail(struct ifaddrs **ifap, struct ifaddrs *ifaddr)
67 {
68 struct ifaddrs *temp = NULL;
69
70 ifaddr->ifa_next = NULL;
71 if (*ifap == NULL) {
72 *ifap = ifaddr;
73 return;
74 }
75
76 for (temp = *ifap; temp->ifa_next != NULL; temp = temp->ifa_next) {
77 /* nothing */
78 }
79
80 temp->ifa_next = ifaddr;
81 }
82
new_ifaddrs_storage(void)83 static struct ifaddrs_storage *new_ifaddrs_storage(void)
84 {
85 struct ifaddrs *ifaddr = NULL;
86 struct ifaddrs_storage *if_storage = NULL;
87
88 if_storage = (struct ifaddrs_storage *)mem_malloc(sizeof(struct ifaddrs_storage));
89 if (if_storage != NULL) {
90 (void)memset_s((void*)if_storage, sizeof(struct ifaddrs_storage), 0, sizeof(struct ifaddrs_storage));
91 ifaddr = &if_storage->ifa;
92 ifaddr->ifa_name = if_storage->name;
93 ifaddr->ifa_addr = &if_storage->addr.sa;
94 ifaddr->ifa_netmask = &if_storage->netmask.sa;
95 ifaddr->ifa_dstaddr = &if_storage->dstaddr.sa;
96 }
97
98 return if_storage;
99 }
100
get_ifa_name(struct netif * netif,struct ifaddrs * ifaddr)101 static int get_ifa_name(struct netif *netif, struct ifaddrs *ifaddr)
102 {
103 int ret;
104
105 if (netif->link_layer_type == LOOPBACK_IF) {
106 ifaddr->ifa_flags |= IFF_LOOPBACK;
107 ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%.2s", netif->name);
108 } else {
109 ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif_get_name(netif));
110 }
111
112 return ret;
113 }
114
115 #if LWIP_IPV4
get_ipv4_ifaddr(struct netif * netif,struct ifaddrs * ifaddr)116 static int get_ipv4_ifaddr(struct netif *netif, struct ifaddrs *ifaddr)
117 {
118 struct sockaddr_in *addr_in = NULL;
119
120 if (netif->flags & NETIF_FLAG_UP) {
121 ifaddr->ifa_flags |= IFF_UP;
122 }
123
124 if (netif->flags & NETIF_FLAG_ETHARP) {
125 ifaddr->ifa_flags = ifaddr->ifa_flags & ((unsigned int)(~IFF_NOARP));
126 } else {
127 ifaddr->ifa_flags |= IFF_NOARP;
128 }
129
130 if (netif->flags & NETIF_FLAG_BROADCAST) {
131 ifaddr->ifa_flags |= IFF_BROADCAST;
132 }
133
134 #if LWIP_DHCP
135 if (dhcp_supplied_address(netif)) {
136 ifaddr->ifa_flags |= IFF_DYNAMIC;
137 }
138 #endif
139
140 #if LWIP_IGMP
141 if (netif->flags & NETIF_FLAG_IGMP) {
142 ifaddr->ifa_flags |= IFF_MULTICAST;
143 }
144 #endif
145
146 if (netif->flags & NETIF_FLAG_LINK_UP) {
147 ifaddr->ifa_flags |= IFF_RUNNING;
148 }
149
150 #if LWIP_HAVE_LOOPIF
151 if (netif->link_layer_type == LOOPBACK_IF) {
152 addr_in = (struct sockaddr_in *)ifaddr->ifa_addr;
153 addr_in->sin_family = AF_INET;
154 addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->ip_addr)->addr;
155 } else
156 #endif
157 {
158 addr_in = (struct sockaddr_in *)ifaddr->ifa_addr;
159 addr_in->sin_family = AF_INET;
160 addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->ip_addr)->addr;
161
162 addr_in = (struct sockaddr_in *)ifaddr->ifa_netmask;
163 addr_in->sin_family = AF_INET;
164 addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->netmask)->addr;
165
166 addr_in = (struct sockaddr_in *)ifaddr->ifa_broadaddr;
167 addr_in->sin_family = AF_INET;
168 addr_in->sin_addr.s_addr = (((ip4_addr_t *)&netif->ip_addr)->addr & ((ip4_addr_t *)&netif->netmask)->addr) |
169 ~((ip4_addr_t *)&netif->netmask)->addr;
170 }
171
172 return get_ifa_name(netif, ifaddr);
173 }
174 #endif /* LWIP_IPV4 */
175
176 #if LWIP_IPV6
177 /* Stack support to retrieve the below flags for ipv6
178 IFF_UP
179 IFF_MULTICAST
180 IFF_RUNNING
181 IFF_LOOPBACK
182 */
get_ipv6_ifaddr(struct netif * netif,struct ifaddrs * ifaddr,int tmp_index)183 static int get_ipv6_ifaddr(struct netif *netif, struct ifaddrs *ifaddr, int tmp_index)
184 {
185 struct sockaddr_in6 *addr_in6 = NULL;
186
187 /* As of now supports the below falgs only */
188 if (netif->flags & NETIF_FLAG_UP) {
189 ifaddr->ifa_flags |= IFF_UP;
190 }
191
192 #if LWIP_IPV6_MLD
193 if (netif->flags & NETIF_FLAG_MLD6) {
194 ifaddr->ifa_flags |= IFF_MULTICAST;
195 }
196 #endif
197
198 if (netif->flags & NETIF_FLAG_LINK_UP) {
199 ifaddr->ifa_flags |= IFF_RUNNING;
200 }
201
202 addr_in6 = (struct sockaddr_in6 *)ifaddr->ifa_addr;
203 addr_in6->sin6_family = AF_INET6;
204 inet6_addr_from_ip6addr(&addr_in6->sin6_addr, (ip6_addr_t *)&netif->ip6_addr[tmp_index]);
205
206 return get_ifa_name(netif, ifaddr);
207 }
208 #endif
209
getifaddrs_internal(struct getifaddrs_arg * arg)210 static void getifaddrs_internal(struct getifaddrs_arg *arg)
211 {
212 struct netif *netif = NULL;
213 struct ifaddrs *ifaddr = NULL;
214 struct ifaddrs_storage *if_storage = NULL;
215
216 #if LWIP_IPV6
217 int n;
218 #endif
219
220 arg->ret = ENOMEM;
221 for (netif = netif_list; netif != NULL; netif = netif->next) {
222 #if LWIP_IPV4
223 if_storage = new_ifaddrs_storage();
224 if (if_storage == NULL) {
225 lwip_freeifaddrs(
226 *(arg->ifap)); /* ifap is assigned to NULL in getifaddrs, so garbage value will not be there */
227 arg->ret = ENOMEM;
228 goto RETURN;
229 }
230
231 /* if get one or more netif info, then getifaddrs return 0(OK) */
232 arg->ret = 0;
233 ifaddr = &if_storage->ifa;
234 (void)get_ipv4_ifaddr(netif, ifaddr);
235 ifaddrs_add_tail(arg->ifap, ifaddr);
236 #endif /* LWIP_IPV4 */
237 #if LWIP_IPV6
238 for (n = 0; n < LWIP_IPV6_NUM_ADDRESSES; n++) {
239 if ((netif->ip6_addr_state[n] & IP6_ADDR_VALID) == 0) {
240 continue;
241 }
242 if_storage = new_ifaddrs_storage();
243 if (if_storage == NULL) {
244 lwip_freeifaddrs(
245 *(arg->ifap)); /* ifap is assigned to NULL in getifaddrs, so garbage value will not be there */
246 arg->ret = ENOMEM;
247 goto RETURN;
248 }
249
250 /* if get one or more netif info, then getifaddrs return 0(OK) */
251 arg->ret = 0;
252 ifaddr = &if_storage->ifa;
253 (void)get_ipv6_ifaddr(netif, ifaddr, n);
254 ifaddrs_add_tail(arg->ifap, ifaddr);
255 }
256 #endif
257 }
258
259 RETURN:
260 #if !LWIP_TCPIP_CORE_LOCKING
261 sys_sem_signal(&arg->cb_completed);
262 #endif
263 return;
264 }
265
lwip_getifaddrs(struct ifaddrs ** ifap)266 int lwip_getifaddrs(struct ifaddrs **ifap)
267 {
268 struct getifaddrs_arg arg;
269
270 LWIP_ERROR("lwip_getifaddrs : ifap is NULL", (ifap != NULL), return ERR_ARG);
271 *ifap = NULL;
272
273 if (!tcpip_init_finish) {
274 set_errno(EACCES);
275 return -1;
276 }
277 arg.ret = 0;
278 arg.ifap = ifap;
279
280 #if LWIP_TCPIP_CORE_LOCKING
281 LOCK_TCPIP_CORE();
282 getifaddrs_internal(&arg);
283 UNLOCK_TCPIP_CORE();
284 #else
285
286 if (sys_sem_new(&arg.cb_completed, 0) != ERR_OK) {
287 set_errno(ENOMEM);
288 return -1;
289 }
290
291 tcpip_callback((tcpip_callback_fn)getifaddrs_internal, &arg);
292 (void)sys_arch_sem_wait(&arg.cb_completed, 0);
293 sys_sem_free(&arg.cb_completed);
294 #endif
295
296 if (arg.ret != 0) {
297 set_errno(arg.ret);
298 *ifap = NULL;
299 return -1;
300 }
301
302 return 0;
303 }
304
freeifaddrs_iteration(struct ifaddrs * ifa)305 static void freeifaddrs_iteration(struct ifaddrs *ifa)
306 {
307 if (ifa == NULL) {
308 return;
309 }
310
311 if (ifa->ifa_next != NULL) {
312 freeifaddrs_iteration(ifa->ifa_next);
313 }
314
315 mem_free(ifa);
316 }
317
lwip_freeifaddrs(struct ifaddrs * ifa)318 void lwip_freeifaddrs(struct ifaddrs *ifa)
319 {
320 freeifaddrs_iteration(ifa);
321 }
322
getifaddrs(struct ifaddrs ** ifap)323 int getifaddrs(struct ifaddrs **ifap)
324 {
325 return lwip_getifaddrs(ifap);
326 }
327
freeifaddrs(struct ifaddrs * ifa)328 void freeifaddrs(struct ifaddrs *ifa)
329 {
330 lwip_freeifaddrs(ifa);
331 }
332
333 #endif /* (LWIP_IPV4 || LWIP_IPV6) && LWIP_SOCKET */
334 #endif /* LWIP_IFADDRS */