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