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