• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */