• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: implement BSD APIs : getifaddrs freeifaddrs
15  * Author: none
16  * Create: 2020
17  */
18 #include "lwip/opt.h"
19 
20 #if LWIP_IFADDRS
21 #if (LWIP_IPV4 || LWIP_IPV6) && LWIP_SOCKET
22 #include "netif/ifaddrs.h"
23 
24 #include <string.h>
25 #include <stdlib.h>
26 
27 #include "lwip/sys.h"
28 #include "lwip/tcpip.h"
29 #include "lwip/priv/sockets_priv.h"
30 #include "lwip/mem.h"
31 
32 struct ifaddrs_storage {
33   struct ifaddrs ifa;
34   union {
35     struct sockaddr sa;
36     struct sockaddr_in s4;
37 #if LWIP_IPV6
38     struct sockaddr_in6 s6;
39 #endif
40   } addr, netmask, dstaddr;
41   char name[IFNAMSIZ];
42 };
43 
44 struct getifaddrs_arg {
45   struct ifaddrs **ifap;
46   sys_sem_t cb_completed;
47   int ret;
48 };
49 
ifaddrs_add_tail(struct ifaddrs ** ifap,struct ifaddrs * ifaddr)50 static void ifaddrs_add_tail(struct ifaddrs **ifap, struct ifaddrs *ifaddr)
51 {
52   struct ifaddrs *temp = NULL;
53 
54   ifaddr->ifa_next = NULL;
55   if (*ifap == NULL) {
56     *ifap = ifaddr;
57     return;
58   }
59 
60   for (temp = *ifap; temp->ifa_next != NULL; temp = temp->ifa_next) {
61     /* nothing */
62   }
63 
64   temp->ifa_next = ifaddr;
65 }
66 
67 
new_ifaddrs_storage(void)68 static struct ifaddrs_storage *new_ifaddrs_storage(void)
69 {
70   struct ifaddrs *ifaddr = NULL;
71   struct ifaddrs_storage *if_storage = NULL;
72 
73   if_storage = (struct ifaddrs_storage *)mem_malloc(sizeof(struct ifaddrs_storage));
74   if (if_storage != NULL) {
75     (void)memset_s((void *)if_storage, sizeof(struct ifaddrs_storage), 0, sizeof(struct ifaddrs_storage));
76     ifaddr              = &if_storage->ifa;
77     ifaddr->ifa_name    = if_storage->name;
78     ifaddr->ifa_addr    = &if_storage->addr.sa;
79     ifaddr->ifa_netmask = &if_storage->netmask.sa;
80     ifaddr->ifa_dstaddr = &if_storage->dstaddr.sa;
81   }
82 
83   return if_storage;
84 }
85 #if LWIP_IPV4
get_ipv4_ifaddr(struct netif * netif,struct ifaddrs * ifaddr)86 static int get_ipv4_ifaddr(struct netif *netif, struct ifaddrs *ifaddr)
87 {
88     struct sockaddr_in *addr_in = NULL;
89 
90     int ret;
91 
92   if (netif->flags & NETIF_FLAG_UP) {
93     ifaddr->ifa_flags |= IFF_UP;
94   }
95 
96   if (netif->flags & NETIF_FLAG_ETHARP) {
97       ifaddr->ifa_flags = ifaddr->ifa_flags & ((unsigned int)(~IFF_NOARP));
98   } else {
99     ifaddr->ifa_flags |= IFF_NOARP;
100   }
101 
102   if (netif->flags & NETIF_FLAG_BROADCAST) {
103     ifaddr->ifa_flags |= IFF_BROADCAST;
104   }
105 
106   if (netif->flags & NETIF_FLAG_DHCP) {
107     ifaddr->ifa_flags |= IFF_DYNAMIC;
108   }
109 #if LWIP_IGMP
110   if (netif->flags & NETIF_FLAG_IGMP) {
111     ifaddr->ifa_flags |= IFF_MULTICAST;
112   }
113 #endif
114 
115   if (netif->flags & NETIF_FLAG_LINK_UP) {
116     ifaddr->ifa_flags |= IFF_DRV_RUNNING;
117   }
118 
119 #if LWIP_HAVE_LOOPIF
120   if (netif->link_layer_type == LOOPBACK_IF) {
121     ifaddr->ifa_flags |= IFF_LOOPBACK;
122 
123     addr_in = (struct sockaddr_in *)ifaddr->ifa_addr;
124     addr_in->sin_family = AF_INET;
125     addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->ip_addr)->addr;
126   } else
127 #endif
128   {
129     addr_in = (struct sockaddr_in *)ifaddr->ifa_addr;
130     addr_in->sin_family      = AF_INET;
131     addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->ip_addr)->addr;
132 
133     addr_in = (struct sockaddr_in *)ifaddr->ifa_netmask;
134     addr_in->sin_family      = AF_INET;
135     addr_in->sin_addr.s_addr = ((ip4_addr_t *)&netif->netmask)->addr;
136 
137     addr_in = (struct sockaddr_in *)ifaddr->ifa_broadaddr;
138     addr_in->sin_family      = AF_INET;
139     addr_in->sin_addr.s_addr = (((ip4_addr_t *)&netif->ip_addr)->addr & ((ip4_addr_t *)&netif->netmask)->addr) |
140                                   ~((ip4_addr_t *)&netif->netmask)->addr;
141   }
142 
143   /* This function returns the loopback interface name as lo0 but as per linux implementation ,
144     the name should be lo Begin */
145   if (netif->link_layer_type == LOOPBACK_IF) {
146     ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name);
147   } else {
148     ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s%"U8_F, netif->name, netif->num);
149   }
150 
151   return ret;
152 }
153 #endif /* LWIP_IPV4 */
154 
155 #if LWIP_IPV6
156 /* Stack support to retrieve the below flags for ipv6
157 IFF_UP
158 IFF_MULTICAST
159 IFF_DRV_RUNNING
160 IFF_LOOPBACK
161 */
get_ipv6_ifaddr(struct netif * netif,struct ifaddrs * ifaddr,int tmp_index)162 static int get_ipv6_ifaddr(struct netif *netif, struct ifaddrs *ifaddr, int tmp_index)
163 {
164   struct sockaddr_in6 *addr_in6 = NULL;
165   int ret;
166 
167     /* As of now supports the below flags only */
168   if (netif->flags & NETIF_FLAG_UP) {
169     ifaddr->ifa_flags |= IFF_UP;
170   }
171 
172 #if LWIP_IPV6_MLD
173   if (netif->flags & NETIF_FLAG_MLD6) {
174     ifaddr->ifa_flags |= IFF_MULTICAST;
175   }
176 #endif
177 
178   if (netif->flags & NETIF_FLAG_LINK_UP) {
179     ifaddr->ifa_flags |= IFF_DRV_RUNNING;
180   }
181 
182   addr_in6 = (struct sockaddr_in6 *)ifaddr->ifa_addr;
183 
184   addr_in6->sin6_family = AF_INET6;
185   inet6_addr_from_ip6addr(&addr_in6->sin6_addr, (ip6_addr_t *)&netif->ip6_addr[tmp_index]);
186 
187   /* This function returns the loopback interface name as lo0 but as per linux implementation ,
188     the name should be lo Begin */
189   if (netif->link_layer_type == LOOPBACK_IF) {
190     ifaddr->ifa_flags   |= IFF_LOOPBACK;
191     ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name);
192   } else {
193     ret = snprintf_s(ifaddr->ifa_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s%"U8_F, netif->name, netif->num);
194   }
195 
196     return ret;
197 }
198 #endif
199 
getifaddrs_internal(struct getifaddrs_arg * arg)200 static void getifaddrs_internal(struct getifaddrs_arg *arg)
201 {
202   struct netif *netif = NULL;
203   struct ifaddrs *ifaddr = NULL;
204   struct ifaddrs_storage *if_storage = NULL;
205 
206 #if LWIP_IPV6
207   int n;
208 #endif
209 
210   arg->ret = ENOMEM;
211 
212   for (netif = netif_list; netif != NULL; netif = netif->next) {
213 #if LWIP_IPV4
214     if_storage = new_ifaddrs_storage();
215     if (if_storage == NULL) {
216       lwip_freeifaddrs(*(arg->ifap)); /* ifap is assigned to NULL in getifaddrs, so garbage value will not be there */
217       arg->ret = ENOMEM;
218       goto RETURN;
219     }
220 
221     /* if get one or more netif info, then getifaddrs return 0(OK) */
222     arg->ret = 0;
223     ifaddr = &if_storage->ifa;
224     (void)get_ipv4_ifaddr(netif, ifaddr);
225     ifaddrs_add_tail(arg->ifap, ifaddr);
226 #endif /* LWIP_IPV4 */
227 #if LWIP_IPV6
228     for (n = 0; n < LWIP_IPV6_NUM_ADDRESSES; n++) {
229       if ((netif->ip6_addr_state[n] & IP6_ADDR_VALID) == 0) {
230         continue;
231       }
232       if_storage = new_ifaddrs_storage();
233       if (if_storage == NULL) {
234         lwip_freeifaddrs(*(arg->ifap)); /* ifap is assigned to NULL in getifaddrs, so garbage value will not be there */
235         arg->ret = ENOMEM;
236         goto RETURN;
237       }
238 
239       /* if get one or more netif info, then getifaddrs return 0(OK) */
240       arg->ret = 0;
241       ifaddr = &if_storage->ifa;
242       (void)get_ipv6_ifaddr(netif, ifaddr, n);
243       ifaddrs_add_tail(arg->ifap, ifaddr);
244     }
245 #endif
246   }
247 
248   RETURN:
249 #if !LWIP_TCPIP_CORE_LOCKING
250   sys_sem_signal(&arg->cb_completed);
251 #endif
252   return;
253 }
254 
lwip_getifaddrs(struct ifaddrs ** ifap)255 int lwip_getifaddrs(struct ifaddrs **ifap)
256 {
257   struct getifaddrs_arg arg;
258 
259   LWIP_ERROR("lwip_getifaddrs : ifap is NULL", (ifap != NULL), return ERR_ARG);
260   *ifap = NULL;
261 
262   if (!tcpip_init_finish) {
263     set_errno(EACCES);
264     return -1;
265   }
266   arg.ret  = 0;
267   arg.ifap = ifap;
268 
269 #if LWIP_TCPIP_CORE_LOCKING
270   LOCK_TCPIP_CORE();
271   getifaddrs_internal(&arg);
272   UNLOCK_TCPIP_CORE();
273 #else
274 
275   if (sys_sem_new(&arg.cb_completed, 0) != ERR_OK) {
276     set_errno(ENOMEM);
277     return -1;
278   }
279 
280   tcpip_callback((tcpip_callback_fn)getifaddrs_internal, &arg);
281   (void)sys_arch_sem_wait(&arg.cb_completed, 0);
282   sys_sem_free(&arg.cb_completed);
283 #endif
284 
285   if (arg.ret != 0) {
286     set_errno(arg.ret);
287     return -1;
288   }
289 
290   return 0;
291 }
292 
freeifaddrs_iteration(struct ifaddrs * ifa)293 static void freeifaddrs_iteration(struct ifaddrs *ifa)
294 {
295   if (ifa == NULL) {
296     return;
297   }
298 
299   if (ifa->ifa_next != NULL) {
300     freeifaddrs_iteration(ifa->ifa_next);
301   }
302 
303   mem_free(ifa);
304 }
305 
lwip_freeifaddrs(struct ifaddrs * ifa)306 void lwip_freeifaddrs(struct ifaddrs *ifa)
307 {
308   freeifaddrs_iteration(ifa);
309 }
310 #endif /* (LWIP_IPV4 || LWIP_IPV6) && LWIP_SOCKET */
311 #endif /* LWIP_IFADDRS */
312