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