├── README.md ├── ifaddrs.h └── ifaddrs.c /README.md: -------------------------------------------------------------------------------- 1 | android-ifaddrs 2 | =============== 3 | 4 | An implementation of getifaddrs() for Android, since the NDK does not natively support it. 5 | 6 | Works just like you would expect on regular Linux. License information is present in each file (BSD license). 7 | -------------------------------------------------------------------------------- /ifaddrs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1995, 1999 3 | * Berkeley Software Design, Inc. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 11 | * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND 12 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 13 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 14 | * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE 15 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 16 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 17 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 18 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 19 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 20 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 21 | * SUCH DAMAGE. 22 | * 23 | * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp 24 | */ 25 | 26 | #ifndef _IFADDRS_H_ 27 | #define _IFADDRS_H_ 28 | 29 | struct ifaddrs { 30 | struct ifaddrs *ifa_next; 31 | char *ifa_name; 32 | unsigned int ifa_flags; 33 | struct sockaddr *ifa_addr; 34 | struct sockaddr *ifa_netmask; 35 | struct sockaddr *ifa_dstaddr; 36 | void *ifa_data; 37 | }; 38 | 39 | /* 40 | * This may have been defined in . Note that if is 41 | * to be included it must be included before this header file. 42 | */ 43 | #ifndef ifa_broadaddr 44 | #define ifa_broadaddr ifa_dstaddr /* broadcast address interface */ 45 | #endif 46 | 47 | #include 48 | 49 | __BEGIN_DECLS 50 | extern int getifaddrs(struct ifaddrs **ifap); 51 | extern void freeifaddrs(struct ifaddrs *ifa); 52 | __END_DECLS 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /ifaddrs.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2013, Kenneth MacKay 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without modification, 6 | are permitted provided that the following conditions are met: 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | */ 24 | 25 | #include "ifaddrs.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | typedef struct NetlinkList 38 | { 39 | struct NetlinkList *m_next; 40 | struct nlmsghdr *m_data; 41 | unsigned int m_size; 42 | } NetlinkList; 43 | 44 | static int netlink_socket(void) 45 | { 46 | int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 47 | if(l_socket < 0) 48 | { 49 | return -1; 50 | } 51 | 52 | struct sockaddr_nl l_addr; 53 | memset(&l_addr, 0, sizeof(l_addr)); 54 | l_addr.nl_family = AF_NETLINK; 55 | if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0) 56 | { 57 | close(l_socket); 58 | return -1; 59 | } 60 | 61 | return l_socket; 62 | } 63 | 64 | static int netlink_send(int p_socket, int p_request) 65 | { 66 | char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))]; 67 | memset(l_buffer, 0, sizeof(l_buffer)); 68 | struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer; 69 | struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr); 70 | 71 | l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg)); 72 | l_hdr->nlmsg_type = p_request; 73 | l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; 74 | l_hdr->nlmsg_pid = 0; 75 | l_hdr->nlmsg_seq = p_socket; 76 | l_msg->rtgen_family = AF_UNSPEC; 77 | 78 | struct sockaddr_nl l_addr; 79 | memset(&l_addr, 0, sizeof(l_addr)); 80 | l_addr.nl_family = AF_NETLINK; 81 | return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr))); 82 | } 83 | 84 | static int netlink_recv(int p_socket, void *p_buffer, size_t p_len) 85 | { 86 | struct msghdr l_msg; 87 | struct iovec l_iov = { p_buffer, p_len }; 88 | struct sockaddr_nl l_addr; 89 | int l_result; 90 | 91 | for(;;) 92 | { 93 | l_msg.msg_name = (void *)&l_addr; 94 | l_msg.msg_namelen = sizeof(l_addr); 95 | l_msg.msg_iov = &l_iov; 96 | l_msg.msg_iovlen = 1; 97 | l_msg.msg_control = NULL; 98 | l_msg.msg_controllen = 0; 99 | l_msg.msg_flags = 0; 100 | int l_result = recvmsg(p_socket, &l_msg, 0); 101 | 102 | if(l_result < 0) 103 | { 104 | if(errno == EINTR) 105 | { 106 | continue; 107 | } 108 | return -2; 109 | } 110 | 111 | if(l_msg.msg_flags & MSG_TRUNC) 112 | { // buffer was too small 113 | return -1; 114 | } 115 | return l_result; 116 | } 117 | } 118 | 119 | static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done) 120 | { 121 | size_t l_size = 4096; 122 | void *l_buffer = NULL; 123 | 124 | for(;;) 125 | { 126 | free(l_buffer); 127 | l_buffer = malloc(l_size); 128 | 129 | int l_read = netlink_recv(p_socket, l_buffer, l_size); 130 | *p_size = l_read; 131 | if(l_read == -2) 132 | { 133 | free(l_buffer); 134 | return NULL; 135 | } 136 | if(l_read >= 0) 137 | { 138 | pid_t l_pid = getpid(); 139 | struct nlmsghdr *l_hdr; 140 | 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)) 141 | { 142 | if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) 143 | { 144 | continue; 145 | } 146 | 147 | if(l_hdr->nlmsg_type == NLMSG_DONE) 148 | { 149 | *p_done = 1; 150 | break; 151 | } 152 | 153 | if(l_hdr->nlmsg_type == NLMSG_ERROR) 154 | { 155 | free(l_buffer); 156 | return NULL; 157 | } 158 | } 159 | return l_buffer; 160 | } 161 | 162 | l_size *= 2; 163 | } 164 | } 165 | 166 | static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size) 167 | { 168 | NetlinkList *l_item = malloc(sizeof(NetlinkList)); 169 | l_item->m_next = NULL; 170 | l_item->m_data = p_data; 171 | l_item->m_size = p_size; 172 | return l_item; 173 | } 174 | 175 | static void freeResultList(NetlinkList *p_list) 176 | { 177 | NetlinkList *l_cur; 178 | while(p_list) 179 | { 180 | l_cur = p_list; 181 | p_list = p_list->m_next; 182 | free(l_cur->m_data); 183 | free(l_cur); 184 | } 185 | } 186 | 187 | static NetlinkList *getResultList(int p_socket, int p_request) 188 | { 189 | if(netlink_send(p_socket, p_request) < 0) 190 | { 191 | return NULL; 192 | } 193 | 194 | NetlinkList *l_list = NULL; 195 | NetlinkList *l_end = NULL; 196 | int l_size; 197 | int l_done = 0; 198 | while(!l_done) 199 | { 200 | struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done); 201 | if(!l_hdr) 202 | { // error 203 | freeResultList(l_list); 204 | return NULL; 205 | } 206 | 207 | NetlinkList *l_item = newListItem(l_hdr, l_size); 208 | if(!l_list) 209 | { 210 | l_list = l_item; 211 | } 212 | else 213 | { 214 | l_end->m_next = l_item; 215 | } 216 | l_end = l_item; 217 | } 218 | return l_list; 219 | } 220 | 221 | static size_t maxSize(size_t a, size_t b) 222 | { 223 | return (a > b ? a : b); 224 | } 225 | 226 | static size_t calcAddrLen(sa_family_t p_family, int p_dataSize) 227 | { 228 | switch(p_family) 229 | { 230 | case AF_INET: 231 | return sizeof(struct sockaddr_in); 232 | case AF_INET6: 233 | return sizeof(struct sockaddr_in6); 234 | case AF_PACKET: 235 | return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize); 236 | default: 237 | return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize); 238 | } 239 | } 240 | 241 | static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size) 242 | { 243 | switch(p_family) 244 | { 245 | case AF_INET: 246 | memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size); 247 | break; 248 | case AF_INET6: 249 | memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size); 250 | break; 251 | case AF_PACKET: 252 | memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size); 253 | ((struct sockaddr_ll*)p_dest)->sll_halen = p_size; 254 | break; 255 | default: 256 | memcpy(p_dest->sa_data, p_data, p_size); 257 | break; 258 | } 259 | p_dest->sa_family = p_family; 260 | } 261 | 262 | static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry) 263 | { 264 | if(!*p_resultList) 265 | { 266 | *p_resultList = p_entry; 267 | } 268 | else 269 | { 270 | struct ifaddrs *l_cur = *p_resultList; 271 | while(l_cur->ifa_next) 272 | { 273 | l_cur = l_cur->ifa_next; 274 | } 275 | l_cur->ifa_next = p_entry; 276 | } 277 | } 278 | 279 | static void interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) 280 | { 281 | struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr); 282 | 283 | size_t l_nameSize = 0; 284 | size_t l_addrSize = 0; 285 | size_t l_dataSize = 0; 286 | 287 | size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); 288 | struct rtattr *l_rta; 289 | for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) 290 | { 291 | void *l_rtaData = RTA_DATA(l_rta); 292 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); 293 | switch(l_rta->rta_type) 294 | { 295 | case IFLA_ADDRESS: 296 | case IFLA_BROADCAST: 297 | l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize)); 298 | break; 299 | case IFLA_IFNAME: 300 | l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); 301 | break; 302 | case IFLA_STATS: 303 | l_dataSize += NLMSG_ALIGN(l_rtaSize); 304 | break; 305 | default: 306 | break; 307 | } 308 | } 309 | 310 | struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize + l_dataSize); 311 | memset(l_entry, 0, sizeof(struct ifaddrs)); 312 | l_entry->ifa_name = ""; 313 | 314 | char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); 315 | char *l_addr = l_name + l_nameSize; 316 | char *l_data = l_addr + l_addrSize; 317 | 318 | l_entry->ifa_flags = l_info->ifi_flags; 319 | 320 | l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg)); 321 | for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifinfomsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) 322 | { 323 | void *l_rtaData = RTA_DATA(l_rta); 324 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); 325 | switch(l_rta->rta_type) 326 | { 327 | case IFLA_ADDRESS: 328 | case IFLA_BROADCAST: 329 | { 330 | size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize); 331 | makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); 332 | ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index; 333 | ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type; 334 | if(l_rta->rta_type == IFLA_ADDRESS) 335 | { 336 | l_entry->ifa_addr = (struct sockaddr *)l_addr; 337 | } 338 | else 339 | { 340 | l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; 341 | } 342 | l_addr += NLMSG_ALIGN(l_addrLen); 343 | break; 344 | } 345 | case IFLA_IFNAME: 346 | strncpy(l_name, l_rtaData, l_rtaDataSize); 347 | l_name[l_rtaDataSize] = '\0'; 348 | l_entry->ifa_name = l_name; 349 | break; 350 | case IFLA_STATS: 351 | memcpy(l_data, l_rtaData, l_rtaDataSize); 352 | l_entry->ifa_data = l_data; 353 | break; 354 | default: 355 | break; 356 | } 357 | } 358 | 359 | addToEnd(p_resultList, l_entry); 360 | p_links[l_info->ifi_index - 1] = l_entry; 361 | } 362 | 363 | static void interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_links, struct ifaddrs **p_resultList) 364 | { 365 | struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr); 366 | 367 | size_t l_nameSize = 0; 368 | size_t l_addrSize = 0; 369 | 370 | int l_addedNetmask = 0; 371 | 372 | size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); 373 | struct rtattr *l_rta; 374 | for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) 375 | { 376 | void *l_rtaData = RTA_DATA(l_rta); 377 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); 378 | if(l_info->ifa_family == AF_PACKET) 379 | { 380 | continue; 381 | } 382 | 383 | switch(l_rta->rta_type) 384 | { 385 | case IFA_ADDRESS: 386 | case IFA_LOCAL: 387 | if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask) 388 | { // make room for netmask 389 | l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); 390 | l_addedNetmask = 1; 391 | } 392 | case IFA_BROADCAST: 393 | l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize)); 394 | break; 395 | case IFA_LABEL: 396 | l_nameSize += NLMSG_ALIGN(l_rtaSize + 1); 397 | break; 398 | default: 399 | break; 400 | } 401 | } 402 | 403 | struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize); 404 | memset(l_entry, 0, sizeof(struct ifaddrs)); 405 | l_entry->ifa_name = p_links[l_info->ifa_index - 1]->ifa_name; 406 | 407 | char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs); 408 | char *l_addr = l_name + l_nameSize; 409 | 410 | l_entry->ifa_flags = l_info->ifa_flags | p_links[l_info->ifa_index - 1]->ifa_flags; 411 | 412 | l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg)); 413 | for(l_rta = (struct rtattr *)(((char *)l_info) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize)) 414 | { 415 | void *l_rtaData = RTA_DATA(l_rta); 416 | size_t l_rtaDataSize = RTA_PAYLOAD(l_rta); 417 | switch(l_rta->rta_type) 418 | { 419 | case IFA_ADDRESS: 420 | case IFA_BROADCAST: 421 | case IFA_LOCAL: 422 | { 423 | size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize); 424 | makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize); 425 | if(l_info->ifa_family == AF_INET6) 426 | { 427 | if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData)) 428 | { 429 | ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index; 430 | } 431 | } 432 | 433 | if(l_rta->rta_type == IFA_ADDRESS) 434 | { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address 435 | if(l_entry->ifa_addr) 436 | { 437 | l_entry->ifa_dstaddr = (struct sockaddr *)l_addr; 438 | } 439 | else 440 | { 441 | l_entry->ifa_addr = (struct sockaddr *)l_addr; 442 | } 443 | } 444 | else if(l_rta->rta_type == IFA_LOCAL) 445 | { 446 | if(l_entry->ifa_addr) 447 | { 448 | l_entry->ifa_dstaddr = l_entry->ifa_addr; 449 | } 450 | l_entry->ifa_addr = (struct sockaddr *)l_addr; 451 | } 452 | else 453 | { 454 | l_entry->ifa_broadaddr = (struct sockaddr *)l_addr; 455 | } 456 | l_addr += NLMSG_ALIGN(l_addrLen); 457 | break; 458 | } 459 | case IFA_LABEL: 460 | strncpy(l_name, l_rtaData, l_rtaDataSize); 461 | l_name[l_rtaDataSize] = '\0'; 462 | l_entry->ifa_name = l_name; 463 | break; 464 | default: 465 | break; 466 | } 467 | } 468 | 469 | if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6)) 470 | { 471 | unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128); 472 | unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen); 473 | char l_mask[16] = {0}; 474 | unsigned i; 475 | for(i=0; i<(l_prefix/8); ++i) 476 | { 477 | l_mask[i] = 0xff; 478 | } 479 | l_mask[i] = 0xff << (8 - (l_prefix % 8)); 480 | 481 | makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8); 482 | l_entry->ifa_netmask = (struct sockaddr *)l_addr; 483 | } 484 | 485 | addToEnd(p_resultList, l_entry); 486 | } 487 | 488 | static void interpret(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_links, struct ifaddrs **p_resultList) 489 | { 490 | pid_t l_pid = getpid(); 491 | for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) 492 | { 493 | unsigned int l_nlsize = p_netlinkList->m_size; 494 | struct nlmsghdr *l_hdr; 495 | for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) 496 | { 497 | if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) 498 | { 499 | continue; 500 | } 501 | 502 | if(l_hdr->nlmsg_type == NLMSG_DONE) 503 | { 504 | break; 505 | } 506 | 507 | if(l_hdr->nlmsg_type == RTM_NEWLINK) 508 | { 509 | interpretLink(l_hdr, p_links, p_resultList); 510 | } 511 | else if(l_hdr->nlmsg_type == RTM_NEWADDR) 512 | { 513 | interpretAddr(l_hdr, p_links, p_resultList); 514 | } 515 | } 516 | } 517 | } 518 | 519 | static unsigned countLinks(int p_socket, NetlinkList *p_netlinkList) 520 | { 521 | unsigned l_links = 0; 522 | pid_t l_pid = getpid(); 523 | for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next) 524 | { 525 | unsigned int l_nlsize = p_netlinkList->m_size; 526 | struct nlmsghdr *l_hdr; 527 | for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize)) 528 | { 529 | if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket) 530 | { 531 | continue; 532 | } 533 | 534 | if(l_hdr->nlmsg_type == NLMSG_DONE) 535 | { 536 | break; 537 | } 538 | 539 | if(l_hdr->nlmsg_type == RTM_NEWLINK) 540 | { 541 | ++l_links; 542 | } 543 | } 544 | } 545 | 546 | return l_links; 547 | } 548 | 549 | int getifaddrs(struct ifaddrs **ifap) 550 | { 551 | if(!ifap) 552 | { 553 | return -1; 554 | } 555 | *ifap = NULL; 556 | 557 | int l_socket = netlink_socket(); 558 | if(l_socket < 0) 559 | { 560 | return -1; 561 | } 562 | 563 | NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK); 564 | if(!l_linkResults) 565 | { 566 | close(l_socket); 567 | return -1; 568 | } 569 | 570 | NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR); 571 | if(!l_addrResults) 572 | { 573 | close(l_socket); 574 | freeResultList(l_linkResults); 575 | return -1; 576 | } 577 | 578 | unsigned l_numLinks = countLinks(l_socket, l_linkResults) + countLinks(l_socket, l_addrResults); 579 | struct ifaddrs *l_links[l_numLinks]; 580 | memset(l_links, 0, l_numLinks * sizeof(struct ifaddrs *)); 581 | 582 | interpret(l_socket, l_linkResults, l_links, ifap); 583 | interpret(l_socket, l_addrResults, l_links, ifap); 584 | 585 | freeResultList(l_linkResults); 586 | freeResultList(l_addrResults); 587 | close(l_socket); 588 | return 0; 589 | } 590 | 591 | void freeifaddrs(struct ifaddrs *ifa) 592 | { 593 | struct ifaddrs *l_cur; 594 | while(ifa) 595 | { 596 | l_cur = ifa; 597 | ifa = ifa->ifa_next; 598 | free(l_cur); 599 | } 600 | } 601 | --------------------------------------------------------------------------------