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