if_index.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. /* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
  2. Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, write to the Free
  14. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  15. 02111-1307 USA.
  16. Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
  17. */
  18. #define __FORCE_GLIBC
  19. #include <features.h>
  20. #include <string.h>
  21. #include <alloca.h>
  22. #include <errno.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <net/if.h>
  27. #include <sys/socket.h>
  28. #include <sys/ioctl.h>
  29. #include <libc-internal.h>
  30. #include "netlinkaccess.h"
  31. libc_hidden_proto(strndup)
  32. libc_hidden_proto(strncpy)
  33. libc_hidden_proto(strdup)
  34. libc_hidden_proto(ioctl)
  35. libc_hidden_proto(close)
  36. extern int __opensock(void) attribute_hidden;
  37. libc_hidden_proto(if_nametoindex)
  38. unsigned int
  39. if_nametoindex(const char* ifname)
  40. {
  41. #ifndef SIOCGIFINDEX
  42. __set_errno (ENOSYS);
  43. return 0;
  44. #else
  45. struct ifreq ifr;
  46. int fd = __opensock();
  47. if (fd < 0)
  48. return 0;
  49. strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
  50. if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
  51. {
  52. int saved_errno = errno;
  53. close(fd);
  54. if (saved_errno == EINVAL)
  55. __set_errno(ENOSYS);
  56. return 0;
  57. }
  58. close(fd);
  59. return ifr.ifr_ifindex;
  60. #endif
  61. }
  62. libc_hidden_def(if_nametoindex)
  63. libc_hidden_proto(if_freenameindex)
  64. void
  65. if_freenameindex (struct if_nameindex *ifn)
  66. {
  67. struct if_nameindex *ptr = ifn;
  68. while (ptr->if_name || ptr->if_index)
  69. {
  70. free (ptr->if_name);
  71. ++ptr;
  72. }
  73. free (ifn);
  74. }
  75. libc_hidden_def(if_freenameindex)
  76. libc_hidden_proto(if_nameindex)
  77. #if !__ASSUME_NETLINK_SUPPORT
  78. struct if_nameindex *
  79. if_nameindex (void)
  80. {
  81. #ifndef SIOCGIFINDEX
  82. __set_errno (ENOSYS);
  83. return NULL;
  84. #else
  85. int fd = __opensock ();
  86. struct ifconf ifc;
  87. unsigned int nifs, i;
  88. int rq_len;
  89. struct if_nameindex *idx = NULL;
  90. # define RQ_IFS 4
  91. if (fd < 0)
  92. return NULL;
  93. ifc.ifc_buf = NULL;
  94. /* Guess on the correct buffer size... */
  95. rq_len = RQ_IFS * sizeof (struct ifreq);
  96. /* Read all the interfaces out of the kernel. */
  97. /* Note: alloca's in this loop are diff from glibc because it's smaller */
  98. do
  99. {
  100. ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
  101. ifc.ifc_len = rq_len;
  102. if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
  103. {
  104. close (fd);
  105. return NULL;
  106. }
  107. }
  108. while (ifc.ifc_len == rq_len);
  109. nifs = ifc.ifc_len / sizeof(struct ifreq);
  110. idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
  111. if (idx == NULL)
  112. {
  113. close(fd);
  114. __set_errno(ENOBUFS);
  115. return NULL;
  116. }
  117. for (i = 0; i < nifs; ++i)
  118. {
  119. struct ifreq *ifr = &ifc.ifc_req[i];
  120. idx[i].if_name = strdup (ifr->ifr_name);
  121. if (idx[i].if_name == NULL
  122. || ioctl (fd, SIOCGIFINDEX, ifr) < 0)
  123. {
  124. int saved_errno = errno;
  125. unsigned int j;
  126. for (j = 0; j < i; ++j)
  127. free (idx[j].if_name);
  128. free(idx);
  129. close(fd);
  130. if (saved_errno == EINVAL)
  131. saved_errno = ENOSYS;
  132. else if (saved_errno == ENOMEM)
  133. saved_errno = ENOBUFS;
  134. __set_errno (saved_errno);
  135. return NULL;
  136. }
  137. idx[i].if_index = ifr->ifr_ifindex;
  138. }
  139. idx[i].if_index = 0;
  140. idx[i].if_name = NULL;
  141. close(fd);
  142. return idx;
  143. #endif
  144. }
  145. #else
  146. struct if_nameindex *
  147. if_nameindex (void)
  148. {
  149. unsigned int nifs = 0;
  150. struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
  151. struct if_nameindex *idx = NULL;
  152. struct netlink_res *nlp;
  153. if (__netlink_open (&nh) < 0)
  154. return NULL;
  155. /* Tell the kernel that we wish to get a list of all
  156. active interfaces. Collect all data for every interface. */
  157. if (__netlink_request (&nh, RTM_GETLINK) < 0)
  158. goto exit_free;
  159. /* Count the interfaces. */
  160. for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
  161. {
  162. struct nlmsghdr *nlh;
  163. size_t size = nlp->size;
  164. if (nlp->nlh == NULL)
  165. continue;
  166. /* Walk through all entries we got from the kernel and look, which
  167. message type they contain. */
  168. for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
  169. {
  170. /* Check if the message is what we want. */
  171. if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
  172. continue;
  173. if (nlh->nlmsg_type == NLMSG_DONE)
  174. break; /* ok */
  175. if (nlh->nlmsg_type == RTM_NEWLINK)
  176. ++nifs;
  177. }
  178. }
  179. idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
  180. if (idx == NULL)
  181. {
  182. nomem:
  183. __set_errno (ENOBUFS);
  184. goto exit_free;
  185. }
  186. /* Add the interfaces. */
  187. nifs = 0;
  188. for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
  189. {
  190. struct nlmsghdr *nlh;
  191. size_t size = nlp->size;
  192. if (nlp->nlh == NULL)
  193. continue;
  194. /* Walk through all entries we got from the kernel and look, which
  195. message type they contain. */
  196. for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
  197. {
  198. /* Check if the message is what we want. */
  199. if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
  200. continue;
  201. if (nlh->nlmsg_type == NLMSG_DONE)
  202. break; /* ok */
  203. if (nlh->nlmsg_type == RTM_NEWLINK)
  204. {
  205. struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
  206. struct rtattr *rta = IFLA_RTA (ifim);
  207. size_t rtasize = IFLA_PAYLOAD (nlh);
  208. idx[nifs].if_index = ifim->ifi_index;
  209. while (RTA_OK (rta, rtasize))
  210. {
  211. char *rta_data = RTA_DATA (rta);
  212. size_t rta_payload = RTA_PAYLOAD (rta);
  213. if (rta->rta_type == IFLA_IFNAME)
  214. {
  215. idx[nifs].if_name = strndup (rta_data, rta_payload);
  216. if (idx[nifs].if_name == NULL)
  217. {
  218. idx[nifs].if_index = 0;
  219. if_freenameindex (idx);
  220. idx = NULL;
  221. goto nomem;
  222. }
  223. break;
  224. }
  225. rta = RTA_NEXT (rta, rtasize);
  226. }
  227. ++nifs;
  228. }
  229. }
  230. }
  231. idx[nifs].if_index = 0;
  232. idx[nifs].if_name = NULL;
  233. exit_free:
  234. __netlink_free_handle (&nh);
  235. __netlink_close (&nh);
  236. return idx;
  237. }
  238. #endif
  239. libc_hidden_def(if_nameindex)
  240. #if 0
  241. struct if_nameindex *
  242. if_nameindex (void)
  243. {
  244. return (if_nameindex_netlink () != NULL ? : if_nameindex_ioctl ());
  245. }
  246. #endif
  247. char *
  248. if_indextoname (unsigned int ifindex, char *ifname)
  249. {
  250. #if !defined SIOCGIFINDEX
  251. __set_errno (ENOSYS);
  252. return NULL;
  253. #else
  254. # ifdef SIOCGIFNAME
  255. /* Use ioctl to avoid searching the list. */
  256. struct ifreq ifr;
  257. int fd;
  258. fd = __opensock ();
  259. if (fd < 0)
  260. return NULL;
  261. ifr.ifr_ifindex = ifindex;
  262. if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
  263. {
  264. int serrno = errno;
  265. close (fd);
  266. if (serrno == ENODEV)
  267. /* POSIX requires ENXIO. */
  268. serrno = ENXIO;
  269. __set_errno (serrno);
  270. return NULL;
  271. }
  272. close (fd);
  273. return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
  274. # else
  275. struct if_nameindex *idx;
  276. struct if_nameindex *p;
  277. char *result = NULL;
  278. idx = if_nameindex();
  279. if (idx != NULL)
  280. {
  281. for (p = idx; p->if_index || p->if_name; ++p)
  282. if (p->if_index == ifindex)
  283. {
  284. result = strncpy (ifname, p->if_name, IFNAMSIZ);
  285. break;
  286. }
  287. if_freenameindex (idx);
  288. if (result == NULL)
  289. __set_errno (ENXIO);
  290. }
  291. return result;
  292. # endif
  293. #endif
  294. }