chiark / gitweb /
mlib2, catacomb2: Update to new releases.
[termux-packages] / ndk-patches / ifaddrs.h
1 /*
2  * Copyright (c) 1995, 1999
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *
11  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
12  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
13  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
14  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
15  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
16  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
17  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
19  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
20  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
21  * SUCH DAMAGE.
22  *
23  *      BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
24  */
25 /*
26 Copyright (c) 2013, Kenneth MacKay
27 All rights reserved.
28
29 Redistribution and use in source and binary forms, with or without modification,
30 are permitted provided that the following conditions are met:
31  * Redistributions of source code must retain the above copyright notice, this
32    list of conditions and the following disclaimer.
33  * Redistributions in binary form must reproduce the above copyright notice,
34    this list of conditions and the following disclaimer in the documentation
35    and/or other materials provided with the distribution.
36
37 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
38 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
41 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
42 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
44 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
45 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 */
48
49 #ifndef _IFADDRS_H_
50 #define _IFADDRS_H_
51
52 struct ifaddrs {
53         struct ifaddrs  *ifa_next;
54         char            *ifa_name;
55         unsigned int     ifa_flags;
56         struct sockaddr *ifa_addr;
57         struct sockaddr *ifa_netmask;
58         struct sockaddr *ifa_dstaddr;
59         void            *ifa_data;
60 };
61
62 /*
63  * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
64  * to be included it must be included before this header file.
65  */
66 #ifndef ifa_broadaddr
67 #define ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
68 #endif
69
70 #include <sys/cdefs.h>
71
72 __BEGIN_DECLS
73 static int getifaddrs(struct ifaddrs **ifap);
74 static void freeifaddrs(struct ifaddrs *ifa);
75 __END_DECLS
76
77 #endif
78
79
80 #include <string.h>
81 #include <stdlib.h>
82 #include <stddef.h>
83 #include <errno.h>
84 #include <unistd.h>
85 #include <sys/socket.h>
86 #include <netpacket/packet.h>
87 #include <net/if_arp.h>
88 #include <netinet/in.h>
89 #include <linux/netlink.h>
90 #include <linux/rtnetlink.h>
91
92 typedef struct NetlinkList {
93     struct NetlinkList *m_next;
94     struct nlmsghdr *m_data;
95     unsigned int m_size;
96 } NetlinkList;
97
98 static int netlink_socket(void)
99 {
100     int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
101     if (l_socket < 0) return -1;
102
103     struct sockaddr_nl l_addr;
104     memset(&l_addr, 0, sizeof(l_addr));
105     l_addr.nl_family = AF_NETLINK;
106     if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) {
107         close(l_socket);
108         return -1;
109     }
110
111     return l_socket;
112 }
113
114 static int netlink_send(int p_socket, int p_request)
115 {
116     struct {
117         struct nlmsghdr m_hdr;
118         struct rtgenmsg m_msg;
119     } l_data;
120
121     memset(&l_data, 0, sizeof(l_data));
122
123     l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
124     l_data.m_hdr.nlmsg_type = p_request;
125     l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
126     l_data.m_hdr.nlmsg_pid = 0;
127     l_data.m_hdr.nlmsg_seq = p_socket;
128     l_data.m_msg.rtgen_family = AF_UNSPEC;
129
130     struct sockaddr_nl l_addr;
131     memset(&l_addr, 0, sizeof(l_addr));
132     l_addr.nl_family = AF_NETLINK;
133     return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
134 }
135
136 static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
137 {
138     struct msghdr l_msg;
139     struct iovec l_iov = { p_buffer, p_len };
140     struct sockaddr_nl l_addr;
141
142     for (;;) {
143         l_msg.msg_name = (void *)&l_addr;
144         l_msg.msg_namelen = sizeof(l_addr);
145         l_msg.msg_iov = &l_iov;
146         l_msg.msg_iovlen = 1;
147         l_msg.msg_control = NULL;
148         l_msg.msg_controllen = 0;
149         l_msg.msg_flags = 0;
150         int l_result = recvmsg(p_socket, &l_msg, 0);
151
152         if (l_result < 0) {
153             if (errno == EINTR) {
154                 continue;
155             }
156             return -2;
157         }
158
159         if (l_msg.msg_flags & MSG_TRUNC) {
160             /* Buffer was too small. */
161             return -1;
162         }
163         return l_result;
164     }
165 }
166
167 static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
168 {
169     size_t l_size = 4096;
170     void *l_buffer = NULL;
171
172     for(;;) {
173         free(l_buffer);
174         l_buffer = malloc(l_size);
175         if (l_buffer == NULL) return NULL;
176
177         int l_read = netlink_recv(p_socket, l_buffer, l_size);
178         *p_size = l_read;
179         if (l_read == -2) {
180             free(l_buffer);
181             return NULL;
182         }
183         if (l_read >= 0) {
184             pid_t l_pid = getpid();
185             struct nlmsghdr *l_hdr;
186             for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read)) {
187                 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
188
189                 if(l_hdr->nlmsg_type == NLMSG_DONE) {
190                     *p_done = 1;
191                     break;
192                 }
193
194                 if(l_hdr->nlmsg_type == NLMSG_ERROR) {
195                     free(l_buffer);
196                     return NULL;
197                 }
198             }
199             return (struct nlmsghdr*)l_buffer;
200         }
201
202         l_size *= 2;
203     }
204 }
205
206 static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
207 {
208     NetlinkList *l_item = (NetlinkList*)malloc(sizeof(NetlinkList));
209     if (l_item == NULL) return NULL;
210
211     l_item->m_next = NULL;
212     l_item->m_data = p_data;
213     l_item->m_size = p_size;
214     return l_item;
215 }
216
217 static void freeResultList(NetlinkList *p_list)
218 {
219     NetlinkList *l_cur;
220     while (p_list) {
221         l_cur = p_list;
222         p_list = p_list->m_next;
223         free(l_cur->m_data);
224         free(l_cur);
225     }
226 }
227
228 static NetlinkList *getResultList(int p_socket, int p_request)
229 {
230     if (netlink_send(p_socket, p_request) < 0) return NULL;
231
232     NetlinkList *l_list = NULL;
233     NetlinkList *l_end = NULL;
234     int l_size;
235     int l_done = 0;
236     while (!l_done) {
237         struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
238         if (!l_hdr) {
239             freeResultList(l_list);
240             return NULL;
241         }
242
243         NetlinkList *l_item = newListItem(l_hdr, l_size);
244         if (!l_item) {
245             freeResultList(l_list);
246             return NULL;
247         }
248         if (!l_list) {
249             l_list = l_item;
250         } else {
251             l_end->m_next = l_item;
252         }
253         l_end = l_item;
254     }
255     return l_list;
256 }
257
258 static size_t maxSize(size_t a, size_t b)
259 {
260     return (a > b ? a : b);
261 }
262
263 static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
264 {
265     switch (p_family) {
266         case AF_INET:
267             return sizeof(struct sockaddr_in);
268         case AF_INET6:
269             return sizeof(struct sockaddr_in6);
270         case AF_PACKET:
271             return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
272         default:
273             return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
274     }
275 }
276
277 static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
278 {
279     switch (p_family) {
280         case AF_INET:
281             memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
282             break;
283         case AF_INET6:
284             memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
285             break;
286         case AF_PACKET:
287             memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
288             ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
289             break;
290         default:
291             memcpy(p_dest->sa_data, p_data, p_size);
292             break;
293     }
294     p_dest->sa_family = p_family;
295 }
296
297 static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
298 {
299     if (!*p_resultList) {
300         *p_resultList = p_entry;
301     } else {
302         struct ifaddrs *l_cur = *p_resultList;
303         while(l_cur->ifa_next) {
304             l_cur = l_cur->ifa_next;
305         }
306         l_cur->ifa_next = p_entry;
307     }
308 }
309
310 static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
311 {
312     struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
313
314     size_t l_nameSize = 0;
315     size_t l_addrSize = 0;
316     size_t l_dataSize = 0;
317
318     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
319     struct rtattr *l_rta;
320     for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
321         void *l_rtaData = RTA_DATA(l_rta);
322         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
323         switch (l_rta->rta_type) {
324             case IFLA_ADDRESS:
325             case IFLA_BROADCAST:
326                 l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
327                 break;
328             case IFLA_IFNAME:
329                 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
330                 break;
331             case IFLA_STATS:
332                 l_dataSize += NLMSG_ALIGN(l_rtaSize);
333                 break;
334             default:
335                 break;
336         }
337     }
338
339     struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
340     if (l_entry == NULL) return -1;
341     memset(l_entry, 0, sizeof(struct ifaddrs));
342     l_entry->ifa_name = (char*)"";
343
344     char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
345     char *l_name = l_index + sizeof(int);
346     char *l_addr = l_name + l_nameSize;
347     char *l_data = l_addr + l_addrSize;
348
349     /* Save the interface index so we can look it up when handling the addresses. */
350     memcpy(l_index, &l_info->ifi_index, sizeof(int));
351
352     l_entry->ifa_flags = l_info->ifi_flags;
353
354     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
355     for (l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
356         void *l_rtaData = RTA_DATA(l_rta);
357         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
358         switch (l_rta->rta_type) {
359             case IFLA_ADDRESS:
360             case IFLA_BROADCAST:
361             {
362                 size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
363                 makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
364                 ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
365                 ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
366                 if (l_rta->rta_type == IFLA_ADDRESS) {
367                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
368                 } else {
369                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
370                 }
371                 l_addr += NLMSG_ALIGN(l_addrLen);
372                 break;
373             }
374             case IFLA_IFNAME:
375                 strncpy(l_name, (char*)l_rtaData, l_rtaDataSize);
376                 l_name[l_rtaDataSize] = '\0';
377                 l_entry->ifa_name = l_name;
378                 break;
379             case IFLA_STATS:
380                 memcpy(l_data, l_rtaData, l_rtaDataSize);
381                 l_entry->ifa_data = l_data;
382                 break;
383             default:
384                 break;
385         }
386     }
387
388     addToEnd(p_resultList, l_entry);
389     return 0;
390 }
391
392 static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
393 {
394     int l_num = 0;
395     struct ifaddrs *l_cur = *p_links;
396     while (l_cur && l_num < p_numLinks) {
397         char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
398         int l_index;
399         memcpy(&l_index, l_indexPtr, sizeof(int));
400         if(l_index == p_index) return l_cur;
401
402         l_cur = l_cur->ifa_next;
403         ++l_num;
404     }
405     return NULL;
406 }
407
408 static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
409 {
410     struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
411     struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
412
413     if (l_info->ifa_family == AF_PACKET) return 0;
414
415     size_t l_nameSize = 0;
416     size_t l_addrSize = 0;
417     int l_addedNetmask = 0;
418
419     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
420     struct rtattr *l_rta;
421     for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
422         void *l_rtaData = RTA_DATA(l_rta);
423         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
424
425         switch (l_rta->rta_type) {
426             case IFA_ADDRESS:
427             case IFA_LOCAL:
428                 if ((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) {
429                     /* Make room for netmask. */
430                     l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
431                     l_addedNetmask = 1;
432                 }
433             case IFA_BROADCAST:
434                 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
435                 break;
436             case IFA_LABEL:
437                 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
438                 break;
439             default:
440                 break;
441         }
442     }
443
444     struct ifaddrs *l_entry = (struct ifaddrs*)malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
445     if (l_entry == NULL) return -1;
446     memset(l_entry, 0, sizeof(struct ifaddrs));
447     l_entry->ifa_name = (l_interface ? l_interface->ifa_name : (char*)"");
448
449     char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
450     char *l_addr = l_name + l_nameSize;
451
452     l_entry->ifa_flags = l_info->ifa_flags;
453     if (l_interface) {
454         l_entry->ifa_flags |= l_interface->ifa_flags;
455     }
456
457     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
458     for (l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) {
459         void *l_rtaData = RTA_DATA(l_rta);
460         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
461         switch (l_rta->rta_type) {
462             case IFA_ADDRESS:
463             case IFA_BROADCAST:
464             case IFA_LOCAL:
465             {
466                 size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
467                 makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
468                 if (l_info->ifa_family == AF_INET6) {
469                     if (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) {
470                         ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
471                     }
472                 }
473
474                 if (l_rta->rta_type == IFA_ADDRESS) {
475                     /* Apparently in a point-to-point network IFA_ADDRESS contains
476                        the dest address and IFA_LOCAL contains the local address. */
477                     if(l_entry->ifa_addr) {
478                         l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
479                     } else {
480                         l_entry->ifa_addr = (struct sockaddr *)l_addr;
481                     }
482                 } else if (l_rta->rta_type == IFA_LOCAL) {
483                     if(l_entry->ifa_addr) {
484                         l_entry->ifa_dstaddr = l_entry->ifa_addr;
485                     }
486                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
487                 } else {
488                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
489                 }
490                 l_addr += NLMSG_ALIGN(l_addrLen);
491                 break;
492             }
493             case IFA_LABEL:
494                 strncpy(l_name, (char*)l_rtaData, l_rtaDataSize);
495                 l_name[l_rtaDataSize] = '\0';
496                 l_entry->ifa_name = l_name;
497                 break;
498             default:
499                 break;
500         }
501     }
502
503     if (l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) {
504         unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
505         unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
506         char l_mask[16] = {0};
507         unsigned i;
508         for (i=0; i<(l_prefix/8); ++i) {
509             l_mask[i] = 0xff;
510         }
511         if (l_prefix % 8) {
512             l_mask[i] = 0xff << (8 - (l_prefix % 8));
513         }
514
515         makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
516         l_entry->ifa_netmask = (struct sockaddr *)l_addr;
517     }
518
519     addToEnd(p_resultList, l_entry);
520     return 0;
521 }
522
523 static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
524 {
525     int l_numLinks = 0;
526     pid_t l_pid = getpid();
527     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
528         unsigned int l_nlsize = p_netlinkList->m_size;
529         struct nlmsghdr *l_hdr;
530         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
531         {
532             if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
533
534             if (l_hdr->nlmsg_type == NLMSG_DONE) break;
535
536             if (l_hdr->nlmsg_type == RTM_NEWLINK) {
537                 if(interpretLink(l_hdr, p_resultList) == -1) return -1;
538                 ++l_numLinks;
539             }
540         }
541     }
542     return l_numLinks;
543 }
544
545 static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
546 {
547     pid_t l_pid = getpid();
548     for (; p_netlinkList; p_netlinkList = p_netlinkList->m_next) {
549         unsigned int l_nlsize = p_netlinkList->m_size;
550         struct nlmsghdr *l_hdr;
551         for (l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) {
552             if ((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) continue;
553
554             if (l_hdr->nlmsg_type == NLMSG_DONE) break;
555
556             if (l_hdr->nlmsg_type == RTM_NEWADDR) {
557                 if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1) return -1;
558             }
559         }
560     }
561     return 0;
562 }
563
564 static int getifaddrs(struct ifaddrs **ifap)
565 {
566     if (!ifap) return -1;
567     *ifap = NULL;
568
569     int l_socket = netlink_socket();
570     if (l_socket < 0) {
571         return -1;
572     }
573
574     NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
575     if (!l_linkResults) {
576         close(l_socket);
577         return -1;
578     }
579
580     NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
581     if (!l_addrResults) {
582         close(l_socket);
583         freeResultList(l_linkResults);
584         return -1;
585     }
586
587     int l_result = 0;
588     int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
589     if (l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1) {
590         l_result = -1;
591     }
592
593     freeResultList(l_linkResults);
594     freeResultList(l_addrResults);
595     close(l_socket);
596     return l_result;
597 }
598
599 static void freeifaddrs(struct ifaddrs *ifa)
600 {
601     struct ifaddrs *l_cur;
602     while (ifa) {
603         l_cur = ifa;
604         ifa = ifa->ifa_next;
605         free(l_cur);
606     }
607 }