• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "uv/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 #include <linux/if_packet.h>
39 
40 typedef struct NetlinkList
41 {
42     struct NetlinkList *m_next;
43     struct nlmsghdr *m_data;
44     unsigned int m_size;
45 } NetlinkList;
46 
netlink_socket(pid_t * p_pid)47 static int netlink_socket(pid_t *p_pid)
48 {
49     struct sockaddr_nl l_addr;
50     socklen_t l_len;
51 
52     int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
53     if(l_socket < 0)
54     {
55         return -1;
56     }
57 
58     memset(&l_addr, 0, sizeof(l_addr));
59     l_addr.nl_family = AF_NETLINK;
60     if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
61     {
62         close(l_socket);
63         return -1;
64     }
65 
66     l_len = sizeof(l_addr);
67     if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
68     {
69         close(l_socket);
70         return -1;
71     }
72     *p_pid = l_addr.nl_pid;
73 
74     return l_socket;
75 }
76 
netlink_send(int p_socket,int p_request)77 static int netlink_send(int p_socket, int p_request)
78 {
79     char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
80 
81     struct nlmsghdr *l_hdr;
82     struct rtgenmsg *l_msg;
83     struct sockaddr_nl l_addr;
84 
85     memset(l_buffer, 0, sizeof(l_buffer));
86 
87     l_hdr = (struct nlmsghdr *)l_buffer;
88     l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
89 
90     l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
91     l_hdr->nlmsg_type = p_request;
92     l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
93     l_hdr->nlmsg_pid = 0;
94     l_hdr->nlmsg_seq = p_socket;
95     l_msg->rtgen_family = AF_UNSPEC;
96 
97     memset(&l_addr, 0, sizeof(l_addr));
98     l_addr.nl_family = AF_NETLINK;
99     return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
100 }
101 
netlink_recv(int p_socket,void * p_buffer,size_t p_len)102 static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
103 {
104     struct sockaddr_nl l_addr;
105     struct msghdr l_msg;
106 
107     struct iovec l_iov;
108     l_iov.iov_base = p_buffer;
109     l_iov.iov_len = p_len;
110 
111     for(;;)
112     {
113         int l_result;
114         l_msg.msg_name = (void *)&l_addr;
115         l_msg.msg_namelen = sizeof(l_addr);
116         l_msg.msg_iov = &l_iov;
117         l_msg.msg_iovlen = 1;
118         l_msg.msg_control = NULL;
119         l_msg.msg_controllen = 0;
120         l_msg.msg_flags = 0;
121         l_result = recvmsg(p_socket, &l_msg, 0);
122 
123         if(l_result < 0)
124         {
125             if(errno == EINTR)
126             {
127                 continue;
128             }
129             return -2;
130         }
131 
132         /* Buffer was too small */
133         if(l_msg.msg_flags & MSG_TRUNC)
134         {
135             return -1;
136         }
137         return l_result;
138     }
139 }
140 
getNetlinkResponse(int p_socket,pid_t p_pid,int * p_size,int * p_done)141 static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
142 {
143     size_t l_size = 4096;
144     void *l_buffer = NULL;
145 
146     for(;;)
147     {
148         int l_read;
149 
150         uv__free(l_buffer);
151         l_buffer = uv__malloc(l_size);
152         if (l_buffer == NULL)
153         {
154             return NULL;
155         }
156 
157         l_read = netlink_recv(p_socket, l_buffer, l_size);
158         *p_size = l_read;
159         if(l_read == -2)
160         {
161             uv__free(l_buffer);
162             return NULL;
163         }
164         if(l_read >= 0)
165         {
166             struct nlmsghdr *l_hdr;
167             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))
168             {
169                 if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
170                 {
171                     continue;
172                 }
173 
174                 if(l_hdr->nlmsg_type == NLMSG_DONE)
175                 {
176                     *p_done = 1;
177                     break;
178                 }
179 
180                 if(l_hdr->nlmsg_type == NLMSG_ERROR)
181                 {
182                     uv__free(l_buffer);
183                     return NULL;
184                 }
185             }
186             return l_buffer;
187         }
188 
189         l_size *= 2;
190     }
191 }
192 
newListItem(struct nlmsghdr * p_data,unsigned int p_size)193 static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
194 {
195     NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
196     if (l_item == NULL)
197     {
198         return NULL;
199     }
200 
201     l_item->m_next = NULL;
202     l_item->m_data = p_data;
203     l_item->m_size = p_size;
204     return l_item;
205 }
206 
freeResultList(NetlinkList * p_list)207 static void freeResultList(NetlinkList *p_list)
208 {
209     NetlinkList *l_cur;
210     while(p_list)
211     {
212         l_cur = p_list;
213         p_list = p_list->m_next;
214         uv__free(l_cur->m_data);
215         uv__free(l_cur);
216     }
217 }
218 
getResultList(int p_socket,int p_request,pid_t p_pid)219 static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
220 {
221     int l_size;
222     int l_done;
223     NetlinkList *l_list;
224     NetlinkList *l_end;
225 
226     if(netlink_send(p_socket, p_request) < 0)
227     {
228         return NULL;
229     }
230 
231     l_list = NULL;
232     l_end = NULL;
233 
234     l_done = 0;
235     while(!l_done)
236     {
237         NetlinkList *l_item;
238 
239         struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
240         /* Error */
241         if(!l_hdr)
242         {
243             freeResultList(l_list);
244             return NULL;
245         }
246 
247         l_item = newListItem(l_hdr, l_size);
248         if (!l_item)
249         {
250             freeResultList(l_list);
251             return NULL;
252         }
253         if(!l_list)
254         {
255             l_list = l_item;
256         }
257         else
258         {
259             l_end->m_next = l_item;
260         }
261         l_end = l_item;
262     }
263     return l_list;
264 }
265 
maxSize(size_t a,size_t b)266 static size_t maxSize(size_t a, size_t b)
267 {
268     return (a > b ? a : b);
269 }
270 
calcAddrLen(sa_family_t p_family,int p_dataSize)271 static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
272 {
273     switch(p_family)
274     {
275         case AF_INET:
276             return sizeof(struct sockaddr_in);
277         case AF_INET6:
278             return sizeof(struct sockaddr_in6);
279         case AF_PACKET:
280             return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
281         default:
282             return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
283     }
284 }
285 
makeSockaddr(sa_family_t p_family,struct sockaddr * p_dest,void * p_data,size_t p_size)286 static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
287 {
288     switch(p_family)
289     {
290         case AF_INET:
291             memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
292             break;
293         case AF_INET6:
294             memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
295             break;
296         case AF_PACKET:
297             memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
298             ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
299             break;
300         default:
301             memcpy(p_dest->sa_data, p_data, p_size);
302             break;
303     }
304     p_dest->sa_family = p_family;
305 }
306 
addToEnd(struct ifaddrs ** p_resultList,struct ifaddrs * p_entry)307 static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
308 {
309     if(!*p_resultList)
310     {
311         *p_resultList = p_entry;
312     }
313     else
314     {
315         struct ifaddrs *l_cur = *p_resultList;
316         while(l_cur->ifa_next)
317         {
318             l_cur = l_cur->ifa_next;
319         }
320         l_cur->ifa_next = p_entry;
321     }
322 }
323 
interpretLink(struct nlmsghdr * p_hdr,struct ifaddrs ** p_resultList)324 static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
325 {
326     struct ifaddrs *l_entry;
327 
328     char *l_index;
329     char *l_name;
330     char *l_addr;
331     char *l_data;
332 
333     struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
334 
335     size_t l_nameSize = 0;
336     size_t l_addrSize = 0;
337     size_t l_dataSize = 0;
338 
339     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
340     struct rtattr *l_rta;
341     for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
342     {
343         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
344         switch(l_rta->rta_type)
345         {
346             case IFLA_ADDRESS:
347             case IFLA_BROADCAST:
348                 l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
349                 break;
350             case IFLA_IFNAME:
351                 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
352                 break;
353             case IFLA_STATS:
354                 l_dataSize += NLMSG_ALIGN(l_rtaSize);
355                 break;
356             default:
357                 break;
358         }
359     }
360 
361     l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
362     if (l_entry == NULL)
363     {
364         return -1;
365     }
366     memset(l_entry, 0, sizeof(struct ifaddrs));
367     l_entry->ifa_name = "";
368 
369     l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
370     l_name = l_index + sizeof(int);
371     l_addr = l_name + l_nameSize;
372     l_data = l_addr + l_addrSize;
373 
374     /* Save the interface index so we can look it up when handling the
375      * addresses.
376      */
377     memcpy(l_index, &l_info->ifi_index, sizeof(int));
378 
379     l_entry->ifa_flags = l_info->ifi_flags;
380 
381     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
382     for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
383     {
384         void *l_rtaData = RTA_DATA(l_rta);
385         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
386         switch(l_rta->rta_type)
387         {
388             case IFLA_ADDRESS:
389             case IFLA_BROADCAST:
390             {
391                 size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
392                 makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
393                 ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
394                 ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
395                 if(l_rta->rta_type == IFLA_ADDRESS)
396                 {
397                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
398                 }
399                 else
400                 {
401                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
402                 }
403                 l_addr += NLMSG_ALIGN(l_addrLen);
404                 break;
405             }
406             case IFLA_IFNAME:
407                 strncpy(l_name, l_rtaData, l_rtaDataSize);
408                 l_name[l_rtaDataSize] = '\0';
409                 l_entry->ifa_name = l_name;
410                 break;
411             case IFLA_STATS:
412                 memcpy(l_data, l_rtaData, l_rtaDataSize);
413                 l_entry->ifa_data = l_data;
414                 break;
415             default:
416                 break;
417         }
418     }
419 
420     addToEnd(p_resultList, l_entry);
421     return 0;
422 }
423 
findInterface(int p_index,struct ifaddrs ** p_links,int p_numLinks)424 static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
425 {
426     int l_num = 0;
427     struct ifaddrs *l_cur = *p_links;
428     while(l_cur && l_num < p_numLinks)
429     {
430         char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
431         int l_index;
432         memcpy(&l_index, l_indexPtr, sizeof(int));
433         if(l_index == p_index)
434         {
435             return l_cur;
436         }
437 
438         l_cur = l_cur->ifa_next;
439         ++l_num;
440     }
441     return NULL;
442 }
443 
interpretAddr(struct nlmsghdr * p_hdr,struct ifaddrs ** p_resultList,int p_numLinks)444 static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
445 {
446     struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
447     struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
448 
449     size_t l_nameSize = 0;
450     size_t l_addrSize = 0;
451 
452     int l_addedNetmask = 0;
453 
454     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
455     struct rtattr *l_rta;
456     struct ifaddrs *l_entry;
457 
458     char *l_name;
459     char *l_addr;
460 
461     for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
462     {
463         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
464         if(l_info->ifa_family == AF_PACKET)
465         {
466             continue;
467         }
468 
469         switch(l_rta->rta_type)
470         {
471             case IFA_ADDRESS:
472             case IFA_LOCAL:
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 = uv__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         uv__free(l_cur);
711     }
712 }
713