| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 | /* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005   Free Software Foundation, Inc.   This file is part of the GNU C Library.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   The GNU C Library is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General Public   License along with the GNU C Library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.   Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org> */#define __FORCE_GLIBC#include <features.h>#define __USE_GNU#include <string.h>#include <alloca.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <net/if.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <libc-internal.h>#include "netlinkaccess.h"libc_hidden_proto(strndup)libc_hidden_proto(strncpy)libc_hidden_proto(strdup)libc_hidden_proto(ioctl)libc_hidden_proto(close)extern int __opensock(void) attribute_hidden;libc_hidden_proto(if_nametoindex)unsigned intif_nametoindex(const char* ifname) {#ifndef SIOCGIFINDEX  __set_errno (ENOSYS);  return 0;#else  struct ifreq ifr;  int fd = __opensock();  if (fd < 0)    return 0;  strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));  if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)    {      int saved_errno = errno;      close(fd);      if (saved_errno == EINVAL)	__set_errno(ENOSYS);      return 0;    }  close(fd);  return ifr.ifr_ifindex;#endif}libc_hidden_def(if_nametoindex)libc_hidden_proto(if_freenameindex)voidif_freenameindex (struct if_nameindex *ifn){  struct if_nameindex *ptr = ifn;  while (ptr->if_name || ptr->if_index)    {      free (ptr->if_name);      ++ptr;    }  free (ifn);}libc_hidden_def(if_freenameindex)libc_hidden_proto(if_nameindex)#if !__ASSUME_NETLINK_SUPPORTstruct if_nameindex *if_nameindex (void){#ifndef SIOCGIFINDEX  __set_errno (ENOSYS);  return NULL;#else  int fd = __opensock ();  struct ifconf ifc;  unsigned int nifs, i;  int rq_len;  struct if_nameindex *idx = NULL;# define RQ_IFS	4  if (fd < 0)    return NULL;  ifc.ifc_buf = NULL;  /* Guess on the correct buffer size... */  rq_len = RQ_IFS * sizeof (struct ifreq);  /* Read all the interfaces out of the kernel.  */  /* Note: alloca's in this loop are diff from glibc because it's smaller */  do    {      ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);      ifc.ifc_len = rq_len;      if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)	{	  close (fd);	  return NULL;	}    }  while (ifc.ifc_len == rq_len);  nifs = ifc.ifc_len / sizeof(struct ifreq);  idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));  if (idx == NULL)    {      close(fd);      __set_errno(ENOBUFS);      return NULL;    }  for (i = 0; i < nifs; ++i)    {      struct ifreq *ifr = &ifc.ifc_req[i];      idx[i].if_name = strdup (ifr->ifr_name);      if (idx[i].if_name == NULL	  || ioctl (fd, SIOCGIFINDEX, ifr) < 0)	{	  int saved_errno = errno;	  unsigned int j;	  for (j =  0; j < i; ++j)	    free (idx[j].if_name);	  free(idx);	  close(fd);	  if (saved_errno == EINVAL)	    saved_errno = ENOSYS;	  else if (saved_errno == ENOMEM)	    saved_errno = ENOBUFS;	  __set_errno (saved_errno);	  return NULL;	}      idx[i].if_index = ifr->ifr_ifindex;    }  idx[i].if_index = 0;  idx[i].if_name = NULL;  close(fd);  return idx;#endif}#elsestruct if_nameindex *if_nameindex (void){  unsigned int nifs = 0;  struct netlink_handle nh = { 0, 0, 0, NULL, NULL };  struct if_nameindex *idx = NULL;  struct netlink_res *nlp;  if (__netlink_open (&nh) < 0)    return NULL;  /* Tell the kernel that we wish to get a list of all     active interfaces.  Collect all data for every interface.  */  if (__netlink_request (&nh, RTM_GETLINK) < 0)    goto exit_free;  /* Count the interfaces.  */  for (nlp = nh.nlm_list; nlp; nlp = nlp->next)    {      struct nlmsghdr *nlh;      size_t size = nlp->size;      if (nlp->nlh == NULL)	continue;      /* Walk through all entries we got from the kernel and look, which         message type they contain.  */      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))	{	  /* Check if the message is what we want.  */	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)	    continue;	  if (nlh->nlmsg_type == NLMSG_DONE)	    break;		/* ok */	  if (nlh->nlmsg_type == RTM_NEWLINK)	    ++nifs;	}    }  idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));  if (idx == NULL)    {    nomem:      __set_errno (ENOBUFS);      goto exit_free;    }  /* Add the interfaces.  */  nifs = 0;  for (nlp = nh.nlm_list; nlp; nlp = nlp->next)    {      struct nlmsghdr *nlh;      size_t size = nlp->size;      if (nlp->nlh == NULL)	continue;      /* Walk through all entries we got from the kernel and look, which         message type they contain.  */      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))	{	  /* Check if the message is what we want.  */	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)	    continue;	  if (nlh->nlmsg_type == NLMSG_DONE)	    break;		/* ok */	  if (nlh->nlmsg_type == RTM_NEWLINK)	    {	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);	      struct rtattr *rta = IFLA_RTA (ifim);	      size_t rtasize = IFLA_PAYLOAD (nlh);	      idx[nifs].if_index = ifim->ifi_index;	      while (RTA_OK (rta, rtasize))		{		  char *rta_data = RTA_DATA (rta);		  size_t rta_payload = RTA_PAYLOAD (rta);		  if (rta->rta_type == IFLA_IFNAME)		    {		      idx[nifs].if_name = strndup (rta_data, rta_payload);		      if (idx[nifs].if_name == NULL)			{			  idx[nifs].if_index = 0;			  if_freenameindex (idx);			  idx = NULL;			  goto nomem;			}		      break;		    }		  rta = RTA_NEXT (rta, rtasize);		}	      ++nifs;	    }	}    }  idx[nifs].if_index = 0;  idx[nifs].if_name = NULL; exit_free:  __netlink_free_handle (&nh);  __netlink_close (&nh);  return idx;}#endiflibc_hidden_def(if_nameindex)#if 0struct if_nameindex *if_nameindex (void){  return (if_nameindex_netlink () != NULL ? : if_nameindex_ioctl ());}#endifchar *if_indextoname (unsigned int ifindex, char *ifname){#if !defined SIOCGIFINDEX  __set_errno (ENOSYS);  return NULL;#else# ifdef SIOCGIFNAME  /* Use ioctl to avoid searching the list. */  struct ifreq ifr;  int fd;  fd = __opensock ();  if (fd < 0)    return NULL;  ifr.ifr_ifindex = ifindex;  if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)    {      int serrno = errno;      close (fd);      if (serrno == ENODEV)	/* POSIX requires ENXIO.  */	serrno = ENXIO;      __set_errno (serrno);      return NULL;  }  close (fd);  return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);# else  struct if_nameindex *idx;  struct if_nameindex *p;  char *result = NULL;  idx = if_nameindex();  if (idx != NULL)    {      for (p = idx; p->if_index || p->if_name; ++p)	if (p->if_index == ifindex)	  {	    result = strncpy (ifname, p->if_name, IFNAMSIZ);	    break;	  }      if_freenameindex (idx);      if (result == NULL)	__set_errno (ENXIO);    }  return result;# endif#endif}
 |