Back to index

glibc  2.9
ifaddrs.c
Go to the documentation of this file.
00001 /* getifaddrs -- get names and addresses of all network interfaces
00002    Copyright (C) 2002, 2003 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <ifaddrs.h>
00021 #include <net/if.h>
00022 #include <sys/socket.h>
00023 #include <sys/ioctl.h>
00024 #include <unistd.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <errno.h>
00028 #include <netinet/in.h>
00029 
00030 #include "ifreq.h"
00031 
00032 /* Create a linked list of `struct ifaddrs' structures, one for each
00033    network interface on the host machine.  If successful, store the
00034    list in *IFAP and return 0.  On errors, return -1 and set `errno'.  */
00035 int
00036 getifaddrs (struct ifaddrs **ifap)
00037 {
00038   /* This implementation handles only IPv4 interfaces.
00039      The various ioctls below will only work on an AF_INET socket.
00040      Some different mechanism entirely must be used for IPv6.  */
00041   int fd = __socket (AF_INET, SOCK_DGRAM, 0);
00042   struct ifreq *ifreqs;
00043   int nifs;
00044 
00045   if (fd < 0)
00046     return -1;
00047 
00048   __ifreq (&ifreqs, &nifs, fd);
00049   if (ifreqs == NULL)              /* XXX doesn't distinguish error vs none */
00050     {
00051       __close (fd);
00052       return -1;
00053     }
00054 
00055   /* Now we have the list of interfaces and each one's address.
00056      Put it into the expected format and fill in the remaining details.  */
00057   if (nifs == 0)
00058     *ifap = NULL;
00059   else
00060     {
00061       struct
00062       {
00063        struct ifaddrs ia;
00064        struct sockaddr addr, netmask, broadaddr;
00065        char name[IF_NAMESIZE];
00066       } *storage;
00067       struct ifreq *ifr;
00068       int i;
00069 
00070       storage = malloc (nifs * sizeof storage[0]);
00071       if (storage == NULL)
00072        {
00073          __close (fd);
00074          __if_freereq (ifreqs, nifs);
00075          return -1;
00076        }
00077 
00078       i = 0;
00079       ifr = ifreqs;
00080       do
00081        {
00082          /* Fill in pointers to the storage we've already allocated.  */
00083          storage[i].ia.ifa_next = &storage[i + 1].ia;
00084          storage[i].ia.ifa_addr = &storage[i].addr;
00085 
00086          /* Now copy the information we already have from SIOCGIFCONF.  */
00087          storage[i].ia.ifa_name = strncpy (storage[i].name, ifr->ifr_name,
00088                                        sizeof storage[i].name);
00089          storage[i].addr = ifr->ifr_addr;
00090 
00091          /* The SIOCGIFCONF call filled in only the name and address.
00092             Now we must also ask for the other information we need.  */
00093 
00094          if (__ioctl (fd, SIOCGIFFLAGS, ifr) < 0)
00095            break;
00096          storage[i].ia.ifa_flags = ifr->ifr_flags;
00097 
00098          ifr->ifr_addr = storage[i].addr;
00099 
00100          if (__ioctl (fd, SIOCGIFNETMASK, ifr) < 0)
00101            storage[i].ia.ifa_netmask = NULL;
00102          else
00103            {
00104              storage[i].ia.ifa_netmask = &storage[i].netmask;
00105              storage[i].netmask = ifr->ifr_netmask;
00106            }
00107 
00108          if (ifr->ifr_flags & IFF_BROADCAST)
00109            {
00110              ifr->ifr_addr = storage[i].addr;
00111              if (__ioctl (fd, SIOCGIFBRDADDR, ifr) < 0)
00112               storage[i].ia.ifa_broadaddr = NULL;
00113              {
00114               storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
00115               storage[i].broadaddr = ifr->ifr_broadaddr;
00116              }
00117            }
00118          else if (ifr->ifr_flags & IFF_POINTOPOINT)
00119            {
00120              ifr->ifr_addr = storage[i].addr;
00121              if (__ioctl (fd, SIOCGIFDSTADDR, ifr) < 0)
00122               storage[i].ia.ifa_broadaddr = NULL;
00123              else
00124               {
00125                 storage[i].ia.ifa_broadaddr = &storage[i].broadaddr;
00126                 storage[i].broadaddr = ifr->ifr_dstaddr;
00127               }
00128            }
00129          else
00130            storage[i].ia.ifa_broadaddr = NULL;
00131 
00132          storage[i].ia.ifa_data = NULL; /* Nothing here for now.  */
00133 
00134          ifr = __if_nextreq (ifr);
00135        } while (++i < nifs);
00136       if (i < nifs)         /* Broke out early on error.  */
00137        {
00138          __close (fd);
00139          free (storage);
00140          __if_freereq (ifreqs, nifs);
00141          return -1;
00142        }
00143 
00144       storage[i - 1].ia.ifa_next = NULL;
00145 
00146       *ifap = &storage[0].ia;
00147 
00148       __close (fd);
00149       __if_freereq (ifreqs, nifs);
00150     }
00151 
00152   return 0;
00153 }
00154 #ifndef getifaddrs
00155 libc_hidden_def (getifaddrs)
00156 #endif
00157 
00158 void
00159 freeifaddrs (struct ifaddrs *ifa)
00160 {
00161   free (ifa);
00162 }
00163 libc_hidden_def (freeifaddrs)