Imported Upstream version 0.9.2
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / adapter_util / 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 <net/if.h>
26 #include "ifaddrs.h"
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <errno.h>
32 #include <unistd.h>
33 #include <sys/socket.h>
34 #include <netpacket/packet.h>
35 #include <net/if_arp.h>
36 #include <netinet/in.h>
37 #include <linux/netlink.h>
38 #include <linux/rtnetlink.h>
39 #include <sys/ioctl.h>
40
41 typedef struct NetlinkList
42 {
43     struct NetlinkList *m_next;
44     struct nlmsghdr *m_data;
45     unsigned int m_size;
46 } NetlinkList;
47
48 static int netlink_socket(void)
49 {
50     int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
51     if(l_socket < 0)
52     {
53         return -1;
54     }
55
56     struct sockaddr_nl l_addr;
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     return l_socket;
66 }
67
68 static int netlink_send(int p_socket, int p_request)
69 {
70     struct
71     {
72         struct nlmsghdr m_hdr;
73         struct rtgenmsg m_msg;
74     } l_data;
75
76     memset(&l_data, 0, sizeof(l_data));
77
78     l_data.m_hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
79     l_data.m_hdr.nlmsg_type = p_request;
80     l_data.m_hdr.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
81     l_data.m_hdr.nlmsg_pid = 0;
82     l_data.m_hdr.nlmsg_seq = p_socket;
83     l_data.m_msg.rtgen_family = AF_UNSPEC;
84
85     struct sockaddr_nl l_addr;
86     memset(&l_addr, 0, sizeof(l_addr));
87     l_addr.nl_family = AF_NETLINK;
88     return (sendto(p_socket, &l_data.m_hdr, l_data.m_hdr.nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
89 }
90
91 static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
92 {
93     struct msghdr l_msg;
94     struct iovec l_iov = { p_buffer, p_len };
95     struct sockaddr_nl l_addr;
96
97     for(;;)
98     {
99         l_msg.msg_name = (void *)&l_addr;
100         l_msg.msg_namelen = sizeof(l_addr);
101         l_msg.msg_iov = &l_iov;
102         l_msg.msg_iovlen = 1;
103         l_msg.msg_control = NULL;
104         l_msg.msg_controllen = 0;
105         l_msg.msg_flags = 0;
106         int l_result = recvmsg(p_socket, &l_msg, 0);
107
108         if(l_result < 0)
109         {
110             if(errno == EINTR)
111             {
112                 continue;
113             }
114             return -2;
115         }
116
117         if(l_msg.msg_flags & MSG_TRUNC)
118         { // buffer was too small
119             return -1;
120         }
121         return l_result;
122     }
123 }
124
125 static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
126 {
127     size_t l_size = 4096;
128     void *l_buffer = NULL;
129
130     for(;;)
131     {
132         free(l_buffer);
133         l_buffer = malloc(l_size);
134         if (l_buffer == NULL)
135         {
136             return NULL;
137         }
138
139         int l_read = netlink_recv(p_socket, l_buffer, l_size);
140         *p_size = l_read;
141         if(l_read == -2)
142         {
143             free(l_buffer);
144             return NULL;
145         }
146         if(l_read >= 0)
147         {
148             pid_t l_pid = getpid();
149             struct nlmsghdr *l_hdr;
150             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))
151             {
152                 if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
153                 {
154                     continue;
155                 }
156
157                 if(l_hdr->nlmsg_type == NLMSG_DONE)
158                 {
159                     *p_done = 1;
160                     break;
161                 }
162
163                 if(l_hdr->nlmsg_type == NLMSG_ERROR)
164                 {
165                     free(l_buffer);
166                     return NULL;
167                 }
168             }
169             return l_buffer;
170         }
171
172         l_size *= 2;
173     }
174 }
175
176 static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
177 {
178     NetlinkList *l_item = malloc(sizeof(NetlinkList));
179     if (l_item == NULL)
180     {
181         return NULL;
182     }
183
184     l_item->m_next = NULL;
185     l_item->m_data = p_data;
186     l_item->m_size = p_size;
187     return l_item;
188 }
189
190 static void freeResultList(NetlinkList *p_list)
191 {
192     NetlinkList *l_cur;
193     while(p_list)
194     {
195         l_cur = p_list;
196         p_list = p_list->m_next;
197         free(l_cur->m_data);
198         free(l_cur);
199     }
200 }
201
202 static NetlinkList *getResultList(int p_socket, int p_request)
203 {
204     if(netlink_send(p_socket, p_request) < 0)
205     {
206         return NULL;
207     }
208
209     NetlinkList *l_list = NULL;
210     NetlinkList *l_end = NULL;
211     int l_size;
212     int l_done = 0;
213     while(!l_done)
214     {
215         struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
216         if(!l_hdr)
217         { // error
218             freeResultList(l_list);
219             return NULL;
220         }
221
222         NetlinkList *l_item = newListItem(l_hdr, l_size);
223         if (!l_item)
224         {
225             freeResultList(l_list);
226             return NULL;
227         }
228         if(!l_list)
229         {
230             l_list = l_item;
231         }
232         else
233         {
234             l_end->m_next = l_item;
235         }
236         l_end = l_item;
237     }
238     return l_list;
239 }
240
241 static size_t maxSize(size_t a, size_t b)
242 {
243     return (a > b ? a : b);
244 }
245
246 static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
247 {
248     switch(p_family)
249     {
250         case AF_INET:
251             return sizeof(struct sockaddr_in);
252         case AF_INET6:
253             return sizeof(struct sockaddr_in6);
254         case AF_PACKET:
255             return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
256         default:
257             return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
258     }
259 }
260
261 static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
262 {
263     switch(p_family)
264     {
265         case AF_INET:
266             memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
267             break;
268         case AF_INET6:
269             memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
270             break;
271         case AF_PACKET:
272             memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
273             ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
274             break;
275         default:
276             memcpy(p_dest->sa_data, p_data, p_size);
277             break;
278     }
279     p_dest->sa_family = p_family;
280 }
281
282 static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
283 {
284     if(!*p_resultList)
285     {
286         *p_resultList = p_entry;
287     }
288     else
289     {
290         struct ifaddrs *l_cur = *p_resultList;
291         while(l_cur->ifa_next)
292         {
293             l_cur = l_cur->ifa_next;
294         }
295         l_cur->ifa_next = p_entry;
296     }
297 }
298
299 static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
300 {
301     struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
302
303     size_t l_nameSize = 0;
304     size_t l_addrSize = 0;
305     size_t l_dataSize = 0;
306
307     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
308     struct rtattr *l_rta;
309     for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
310     {
311         //void *l_rtaData = RTA_DATA(l_rta);
312         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
313         switch(l_rta->rta_type)
314         {
315             case IFLA_ADDRESS:
316             case IFLA_BROADCAST:
317                 l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
318                 break;
319             case IFLA_IFNAME:
320                 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
321                 break;
322             case IFLA_STATS:
323                 l_dataSize += NLMSG_ALIGN(l_rtaSize);
324                 break;
325             default:
326                 break;
327         }
328     }
329
330     struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
331     if (l_entry == NULL)
332     {
333         return -1;
334     }
335     memset(l_entry, 0, sizeof(struct ifaddrs));
336     l_entry->ifa_name = "";
337
338     char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
339     char *l_name = l_index + sizeof(int);
340     char *l_addr = l_name + l_nameSize;
341     char *l_data = l_addr + l_addrSize;
342
343     // save the interface index so we can look it up when handling the addresses.
344     memcpy(l_index, &l_info->ifi_index, sizeof(int));
345
346     l_entry->ifa_flags = l_info->ifi_flags;
347
348     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
349     for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
350     {
351         void *l_rtaData = RTA_DATA(l_rta);
352         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
353         switch(l_rta->rta_type)
354         {
355             case IFLA_ADDRESS:
356             case IFLA_BROADCAST:
357             {
358                 size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
359                 makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
360                 ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
361                 ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
362                 if(l_rta->rta_type == IFLA_ADDRESS)
363                 {
364                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
365                 }
366                 else
367                 {
368                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
369                 }
370                 l_addr += NLMSG_ALIGN(l_addrLen);
371                 break;
372             }
373             case IFLA_IFNAME:
374                 strncpy(l_name, l_rtaData, l_rtaDataSize);
375                 l_name[l_rtaDataSize] = '\0';
376                 l_entry->ifa_name = l_name;
377                 break;
378             case IFLA_STATS:
379                 memcpy(l_data, l_rtaData, l_rtaDataSize);
380                 l_entry->ifa_data = l_data;
381                 break;
382             default:
383                 break;
384         }
385     }
386
387     addToEnd(p_resultList, l_entry);
388     return 0;
389 }
390
391 static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
392 {
393     int l_num = 0;
394     struct ifaddrs *l_cur = *p_links;
395     while(l_cur && l_num < p_numLinks)
396     {
397         char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
398         int l_index;
399         memcpy(&l_index, l_indexPtr, sizeof(int));
400         if(l_index == p_index)
401         {
402             return l_cur;
403         }
404
405         l_cur = l_cur->ifa_next;
406         ++l_num;
407     }
408     return NULL;
409 }
410
411 static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
412 {
413     struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
414     struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
415
416     if(l_info->ifa_family == AF_PACKET)
417     {
418         return 0;
419     }
420
421     size_t l_nameSize = 0;
422     size_t l_addrSize = 0;
423
424     int l_addedNetmask = 0;
425
426     size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
427     struct rtattr *l_rta;
428     for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
429     {
430         //void *l_rtaData = RTA_DATA(l_rta);
431         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
432
433         switch(l_rta->rta_type)
434         {
435             case IFA_ADDRESS:
436             case IFA_LOCAL:
437                 if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
438                 { // make room for netmask
439                     l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
440                     l_addedNetmask = 1;
441                 }
442             case IFA_BROADCAST:
443                 l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
444                 break;
445             case IFA_LABEL:
446                 l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
447                 break;
448             default:
449                 break;
450         }
451     }
452
453     struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
454     if (l_entry == NULL)
455     {
456         return -1;
457     }
458     memset(l_entry, 0, sizeof(struct ifaddrs));
459     l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
460
461     char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
462     char *l_addr = l_name + l_nameSize;
463
464     l_entry->ifa_flags = l_info->ifa_flags;
465     if(l_interface)
466     {
467         l_entry->ifa_flags |= l_interface->ifa_flags;
468     }
469
470     l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
471     for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
472     {
473         void *l_rtaData = RTA_DATA(l_rta);
474         size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
475         switch(l_rta->rta_type)
476         {
477             case IFA_ADDRESS:
478             case IFA_BROADCAST:
479             case IFA_LOCAL:
480             {
481                 size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
482                 makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
483                 if(l_info->ifa_family == AF_INET6)
484                 {
485                     if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
486                     {
487                         ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
488                     }
489                 }
490
491                 if(l_rta->rta_type == IFA_ADDRESS)
492                 { // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
493                     if(l_entry->ifa_addr)
494                     {
495                         l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
496                     }
497                     else
498                     {
499                         l_entry->ifa_addr = (struct sockaddr *)l_addr;
500                     }
501                 }
502                 else if(l_rta->rta_type == IFA_LOCAL)
503                 {
504                     if(l_entry->ifa_addr)
505                     {
506                         l_entry->ifa_dstaddr = l_entry->ifa_addr;
507                     }
508                     l_entry->ifa_addr = (struct sockaddr *)l_addr;
509                 }
510                 else
511                 {
512                     l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
513                 }
514                 l_addr += NLMSG_ALIGN(l_addrLen);
515                 break;
516             }
517             case IFA_LABEL:
518                 strncpy(l_name, l_rtaData, l_rtaDataSize);
519                 l_name[l_rtaDataSize] = '\0';
520                 l_entry->ifa_name = l_name;
521                 break;
522             default:
523                 break;
524         }
525     }
526
527     if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
528     {
529         unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
530         unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
531         char l_mask[16] = {0};
532         unsigned i;
533         for(i=0; i<(l_prefix/8); ++i)
534         {
535             l_mask[i] = 0xff;
536         }
537         if(l_prefix % 8)
538         {
539             l_mask[i] = 0xff << (8 - (l_prefix % 8));
540         }
541
542         makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
543         l_entry->ifa_netmask = (struct sockaddr *)l_addr;
544     }
545
546     addToEnd(p_resultList, l_entry);
547     return 0;
548 }
549
550 static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
551 {
552     int l_numLinks = 0;
553     pid_t l_pid = getpid();
554     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
555     {
556         unsigned int l_nlsize = p_netlinkList->m_size;
557         struct nlmsghdr *l_hdr;
558         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
559         {
560             if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
561             {
562                 continue;
563             }
564
565             if(l_hdr->nlmsg_type == NLMSG_DONE)
566             {
567                 break;
568             }
569
570             if(l_hdr->nlmsg_type == RTM_NEWLINK)
571             {
572                 if(interpretLink(l_hdr, p_resultList) == -1)
573                 {
574                     return -1;
575                 }
576                 ++l_numLinks;
577             }
578         }
579     }
580     return l_numLinks;
581 }
582
583 static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
584 {
585     pid_t l_pid = getpid();
586     for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
587     {
588         unsigned int l_nlsize = p_netlinkList->m_size;
589         struct nlmsghdr *l_hdr;
590         for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
591         {
592             if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
593             {
594                 continue;
595             }
596
597             if(l_hdr->nlmsg_type == NLMSG_DONE)
598             {
599                 break;
600             }
601
602             if(l_hdr->nlmsg_type == RTM_NEWADDR)
603             {
604                 if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
605                 {
606                     return -1;
607                 }
608             }
609         }
610     }
611     return 0;
612 }
613
614 int getifaddrs(struct ifaddrs **ifap)
615 {
616     if(!ifap)
617     {
618         return -1;
619     }
620     *ifap = NULL;
621
622     int l_socket = netlink_socket();
623     if(l_socket < 0)
624     {
625         return -1;
626     }
627
628     NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
629     if(!l_linkResults)
630     {
631         close(l_socket);
632         return -1;
633     }
634
635     NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
636     if(!l_addrResults)
637     {
638         close(l_socket);
639         freeResultList(l_linkResults);
640         return -1;
641     }
642
643     int l_result = 0;
644     int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
645     if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
646     {
647         l_result = -1;
648     }
649
650     freeResultList(l_linkResults);
651     freeResultList(l_addrResults);
652     close(l_socket);
653     return l_result;
654 }
655
656 void freeifaddrs(struct ifaddrs *ifa)
657 {
658     struct ifaddrs *l_cur;
659     while(ifa)
660     {
661         l_cur = ifa;
662         ifa = ifa->ifa_next;
663         free(l_cur);
664     }
665 }
666
667
668 /*
669  * Copyright (C) 2008 The Android Open Source Project
670  * All rights reserved.
671  *
672  * Redistribution and use in source and binary forms, with or without
673  * modification, are permitted provided that the following conditions
674  * are met:
675  *  * Redistributions of source code must retain the above copyright
676  *    notice, this list of conditions and the following disclaimer.
677  *  * Redistributions in binary form must reproduce the above copyright
678  *    notice, this list of conditions and the following disclaimer in
679  *    the documentation and/or other materials provided with the
680  *    distribution.
681  *
682  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
683  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
684  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
685  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
686  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
687  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
688  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
689  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
690  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
691  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
692  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
693  * SUCH DAMAGE.
694  */
695
696 //#include <string.h>
697 //#include <unistd.h>
698 //#include <linux/sockios.h>
699 //#include <net/if.h>
700 //#include <sys/socket.h>
701 //#include <sys/ioctl.h>
702
703 /*
704  * Map an interface name into its corresponding index.
705  * Returns 0 on error, as 0 is not a valid index.
706  */
707 unsigned int if_nametoindex(const char *ifname)
708 {
709     int index;
710     int ctl_sock;
711     struct ifreq ifr;
712
713     memset(&ifr, 0, sizeof(struct ifreq));
714     strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
715     ifr.ifr_name[IFNAMSIZ - 1] = 0;
716
717     index = 0;
718     if ((ctl_sock = socket(AF_INET, SOCK_DGRAM, 0)) >= 0) {
719         if (ioctl(ctl_sock, SIOCGIFINDEX, &ifr) >= 0) {
720             index = ifr.ifr_ifindex;
721         }
722         close(ctl_sock);
723     }
724     return index;
725 }