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 "android-ifaddrs.h"
27 #include "uv-common.h"
28 
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <sys/socket.h>
34 #include <net/if_arp.h>
35 #include <netinet/in.h>
36 #include <linux/netlink.h>
37 #include <linux/rtnetlink.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         uv__free(l_buffer);
150         l_buffer = uv__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             uv__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                     uv__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 = uv__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         uv__free(l_cur->m_data);
214         uv__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 = uv__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                 if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
473                 {
474                     /* Make room for netmask */
475                     l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
476                     l_addedNetmask = 1;
477                 }
478             case IFA_BROADCAST:
479                 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
480                 break;
481             case IFA_LABEL:
482                 l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
483                 break;
484             default:
485                 break;
486         }
487     }
488 
489     l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
490     if (l_entry == NULL)
491     {
492         return -1;
493     }
494     memset(l_entry, 0, sizeof(struct ifaddrs));
495     l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
496 
497     l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
498     l_addr = l_name + l_nameSize;
499 
500     l_entry->ifa_flags = l_info->ifa_flags;
501     if(l_interface)
502     {
503         l_entry->ifa_flags |= l_interface->ifa_flags;
504     }
505 
506     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
507     for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
508     {
509         void *l_rtaData = RTA_DATA(l_rta);
510         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
511         switch(l_rta->rta_type)
512         {
513             case IFA_ADDRESS:
514             case IFA_BROADCAST:
515             case IFA_LOCAL:
516             {
517                 size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
518                 makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
519                 if(l_info->ifa_family == AF_INET6)
520                 {
521                     if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
522                     {
523                         ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
524                     }
525                 }
526 
527                 /* Apparently in a point-to-point network IFA_ADDRESS contains
528                  * the dest address and IFA_LOCAL contains the local address
529                  */
530                 if(l_rta->rta_type == IFA_ADDRESS)
531                 {
532                     if(l_entry->ifa_addr)
533                     {
534                         l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
535                     }
536                     else
537                     {
538                         l_entry->ifa_addr = (struct sockaddr *)l_addr;
539                     }
540                 }
541                 else if(l_rta->rta_type == IFA_LOCAL)
542                 {
543                     if(l_entry->ifa_addr)
544                     {
545                         l_entry->ifa_dstaddr = l_entry->ifa_addr;
546                     }
547                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
548                 }
549                 else
550                 {
551                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
552                 }
553                 l_addr += NLMSG_ALIGN(l_addrLen);
554                 break;
555             }
556             case IFA_LABEL:
557                 strncpy(l_name, l_rtaData, l_rtaDataSize);
558                 l_name[l_rtaDataSize] = '\0';
559                 l_entry->ifa_name = l_name;
560                 break;
561             default:
562                 break;
563         }
564     }
565 
566     if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
567     {
568         unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
569         unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
570         unsigned char l_mask[16] = {0};
571         unsigned i;
572         for(i=0; i<(l_prefix/8); ++i)
573         {
574             l_mask[i] = 0xff;
575         }
576         if(l_prefix % 8)
577         {
578             l_mask[i] = 0xff << (8 - (l_prefix % 8));
579         }
580 
581         makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
582         l_entry->ifa_netmask = (struct sockaddr *)l_addr;
583     }
584 
585     addToEnd(p_resultList, l_entry);
586     return 0;
587 }
588 
interpretLinks(int p_socket,pid_t p_pid,NetlinkList * p_netlinkList,struct ifaddrs ** p_resultList)589 static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
590 {
591 
592     int l_numLinks = 0;
593     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
594     {
595         unsigned int l_nlsize = p_netlinkList->m_size;
596         struct nlmsghdr *l_hdr;
597         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
598         {
599             if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
600             {
601                 continue;
602             }
603 
604             if(l_hdr->nlmsg_type == NLMSG_DONE)
605             {
606                 break;
607             }
608 
609             if(l_hdr->nlmsg_type == RTM_NEWLINK)
610             {
611                 if(interpretLink(l_hdr, p_resultList) == -1)
612                 {
613                     return -1;
614                 }
615                 ++l_numLinks;
616             }
617         }
618     }
619     return l_numLinks;
620 }
621 
interpretAddrs(int p_socket,pid_t p_pid,NetlinkList * p_netlinkList,struct ifaddrs ** p_resultList,int p_numLinks)622 static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
623 {
624     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
625     {
626         unsigned int l_nlsize = p_netlinkList->m_size;
627         struct nlmsghdr *l_hdr;
628         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
629         {
630             if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
631             {
632                 continue;
633             }
634 
635             if(l_hdr->nlmsg_type == NLMSG_DONE)
636             {
637                 break;
638             }
639 
640             if(l_hdr->nlmsg_type == RTM_NEWADDR)
641             {
642                 if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
643                 {
644                     return -1;
645                 }
646             }
647         }
648     }
649     return 0;
650 }
651 
getifaddrs(struct ifaddrs ** ifap)652 int getifaddrs(struct ifaddrs **ifap)
653 {
654     int l_socket;
655     int l_result;
656     int l_numLinks;
657     pid_t l_pid;
658     NetlinkList *l_linkResults;
659     NetlinkList *l_addrResults;
660 
661     if(!ifap)
662     {
663         return -1;
664     }
665     *ifap = NULL;
666 
667     l_socket = netlink_socket(&l_pid);
668     if(l_socket < 0)
669     {
670         return -1;
671     }
672 
673     l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
674     if(!l_linkResults)
675     {
676         close(l_socket);
677         return -1;
678     }
679 
680     l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
681     if(!l_addrResults)
682     {
683         close(l_socket);
684         freeResultList(l_linkResults);
685         return -1;
686     }
687 
688     l_result = 0;
689     l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
690     if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
691     {
692         l_result = -1;
693     }
694 
695     freeResultList(l_linkResults);
696     freeResultList(l_addrResults);
697     close(l_socket);
698     return l_result;
699 }
700 
freeifaddrs(struct ifaddrs * ifa)701 void freeifaddrs(struct ifaddrs *ifa)
702 {
703     struct ifaddrs *l_cur;
704     while(ifa)
705     {
706         l_cur = ifa;
707         ifa = ifa->ifa_next;
708         uv__free(l_cur);
709     }
710 }
711