ll_map.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * ll_map.c
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version
  8. * 2 of the License, or (at your option) any later version.
  9. *
  10. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  11. *
  12. */
  13. #include <net/if.h> /* struct ifreq and co. */
  14. #include "libbb.h"
  15. #include "libnetlink.h"
  16. #include "ll_map.h"
  17. struct idxmap {
  18. struct idxmap *next;
  19. int index;
  20. int type;
  21. int alen;
  22. unsigned flags;
  23. unsigned char addr[8];
  24. char name[16];
  25. };
  26. static struct idxmap *idxmap[16];
  27. static struct idxmap *find_by_index(int idx)
  28. {
  29. struct idxmap *im;
  30. for (im = idxmap[idx & 0xF]; im; im = im->next)
  31. if (im->index == idx)
  32. return im;
  33. return NULL;
  34. }
  35. int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
  36. {
  37. int h;
  38. struct ifinfomsg *ifi = NLMSG_DATA(n);
  39. struct idxmap *im, **imp;
  40. struct rtattr *tb[IFLA_MAX+1];
  41. if (n->nlmsg_type != RTM_NEWLINK)
  42. return 0;
  43. if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
  44. return -1;
  45. memset(tb, 0, sizeof(tb));
  46. parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
  47. if (tb[IFLA_IFNAME] == NULL)
  48. return 0;
  49. h = ifi->ifi_index & 0xF;
  50. for (imp = &idxmap[h]; (im = *imp) != NULL; imp = &im->next)
  51. if (im->index == ifi->ifi_index)
  52. goto found;
  53. im = xmalloc(sizeof(*im));
  54. im->next = *imp;
  55. im->index = ifi->ifi_index;
  56. *imp = im;
  57. found:
  58. im->type = ifi->ifi_type;
  59. im->flags = ifi->ifi_flags;
  60. if (tb[IFLA_ADDRESS]) {
  61. int alen;
  62. im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
  63. if (alen > sizeof(im->addr))
  64. alen = sizeof(im->addr);
  65. memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
  66. } else {
  67. im->alen = 0;
  68. memset(im->addr, 0, sizeof(im->addr));
  69. }
  70. strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
  71. return 0;
  72. }
  73. const char *ll_idx_n2a(int idx, char *buf)
  74. {
  75. struct idxmap *im;
  76. if (idx == 0)
  77. return "*";
  78. im = find_by_index(idx);
  79. if (im)
  80. return im->name;
  81. snprintf(buf, 16, "if%d", idx);
  82. return buf;
  83. }
  84. const char *ll_index_to_name(int idx)
  85. {
  86. static char nbuf[16];
  87. return ll_idx_n2a(idx, nbuf);
  88. }
  89. #ifdef UNUSED
  90. int ll_index_to_type(int idx)
  91. {
  92. struct idxmap *im;
  93. if (idx == 0)
  94. return -1;
  95. im = find_by_index(idx);
  96. if (im)
  97. return im->type;
  98. return -1;
  99. }
  100. #endif
  101. unsigned ll_index_to_flags(int idx)
  102. {
  103. struct idxmap *im;
  104. if (idx == 0)
  105. return 0;
  106. im = find_by_index(idx);
  107. if (im)
  108. return im->flags;
  109. return 0;
  110. }
  111. int xll_name_to_index(const char *const name)
  112. {
  113. int ret = 0;
  114. int sock_fd;
  115. /* caching is not warranted - no users which repeatedly call it */
  116. #ifdef UNUSED
  117. static char ncache[16];
  118. static int icache;
  119. struct idxmap *im;
  120. int i;
  121. if (name == NULL)
  122. goto out;
  123. if (icache && strcmp(name, ncache) == 0) {
  124. ret = icache;
  125. goto out;
  126. }
  127. for (i = 0; i < 16; i++) {
  128. for (im = idxmap[i]; im; im = im->next) {
  129. if (strcmp(im->name, name) == 0) {
  130. icache = im->index;
  131. strcpy(ncache, name);
  132. ret = im->index;
  133. goto out;
  134. }
  135. }
  136. }
  137. /* We have not found the interface in our cache, but the kernel
  138. * may still know about it. One reason is that we may be using
  139. * module on-demand loading, which means that the kernel will
  140. * load the module and make the interface exist only when
  141. * we explicitely request it (check for dev_load() in net/core/dev.c).
  142. * I can think of other similar scenario, but they are less common...
  143. * Jean II */
  144. #endif
  145. sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
  146. if (sock_fd) {
  147. struct ifreq ifr;
  148. int tmp;
  149. strncpy(ifr.ifr_name, name, IFNAMSIZ);
  150. ifr.ifr_ifindex = -1;
  151. tmp = ioctl(sock_fd, SIOCGIFINDEX, &ifr);
  152. close(sock_fd);
  153. if (tmp >= 0)
  154. /* In theory, we should redump the interface list
  155. * to update our cache, this is left as an exercise
  156. * to the reader... Jean II */
  157. ret = ifr.ifr_ifindex;
  158. }
  159. /* out:*/
  160. if (ret <= 0)
  161. bb_error_msg_and_die("cannot find device \"%s\"", name);
  162. return ret;
  163. }
  164. int ll_init_map(struct rtnl_handle *rth)
  165. {
  166. xrtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK);
  167. xrtnl_dump_filter(rth, ll_remember_index, &idxmap);
  168. return 0;
  169. }