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