nameif.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * nameif.c - Naming Interfaces based on MAC address for busybox.
  4. *
  5. * Written 2000 by Andi Kleen.
  6. * Busybox port 2002 by Nick Fedchik <nick@fedchik.org.ua>
  7. * Glenn McGrath
  8. * Extended matching support 2008 by Nico Erfurth <masta@perlgolf.de>
  9. *
  10. * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  11. */
  12. #include "libbb.h"
  13. #include <syslog.h>
  14. #include <net/if.h>
  15. #include <netinet/ether.h>
  16. #include <linux/sockios.h>
  17. #ifndef IFNAMSIZ
  18. #define IFNAMSIZ 16
  19. #endif
  20. /* Taken from linux/sockios.h */
  21. #define SIOCSIFNAME 0x8923 /* set interface name */
  22. /* Octets in one Ethernet addr, from <linux/if_ether.h> */
  23. #define ETH_ALEN 6
  24. #ifndef ifr_newname
  25. #define ifr_newname ifr_ifru.ifru_slave
  26. #endif
  27. typedef struct ethtable_s {
  28. struct ethtable_s *next;
  29. struct ethtable_s *prev;
  30. char *ifname;
  31. struct ether_addr *mac;
  32. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  33. char *bus_info;
  34. char *driver;
  35. #endif
  36. } ethtable_t;
  37. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  38. /* Cut'n'paste from ethtool.h */
  39. #define ETHTOOL_BUSINFO_LEN 32
  40. /* these strings are set to whatever the driver author decides... */
  41. struct ethtool_drvinfo {
  42. uint32_t cmd;
  43. char driver[32]; /* driver short name, "tulip", "eepro100" */
  44. char version[32]; /* driver version string */
  45. char fw_version[32]; /* firmware version string, if applicable */
  46. char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
  47. /* For PCI devices, use pci_dev->slot_name. */
  48. char reserved1[32];
  49. char reserved2[16];
  50. uint32_t n_stats; /* number of u64's from ETHTOOL_GSTATS */
  51. uint32_t testinfo_len;
  52. uint32_t eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
  53. uint32_t regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
  54. };
  55. #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
  56. #endif
  57. static void nameif_parse_selector(ethtable_t *ch, char *selector)
  58. {
  59. struct ether_addr *lmac;
  60. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  61. int found_selector = 0;
  62. while (*selector) {
  63. char *next;
  64. #endif
  65. selector = skip_whitespace(selector);
  66. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  67. if (*selector == '\0')
  68. break;
  69. /* Search for the end .... */
  70. next = skip_non_whitespace(selector);
  71. if (*next)
  72. *next++ = '\0';
  73. /* Check for selectors, mac= is assumed */
  74. if (strncmp(selector, "bus=", 4) == 0) {
  75. ch->bus_info = xstrdup(selector + 4);
  76. found_selector++;
  77. } else if (strncmp(selector, "driver=", 7) == 0) {
  78. ch->driver = xstrdup(selector + 7);
  79. found_selector++;
  80. } else {
  81. #endif
  82. lmac = xmalloc(ETH_ALEN);
  83. ch->mac = ether_aton_r(selector + (strncmp(selector, "mac=", 4) ? 0 : 4), lmac);
  84. if (ch->mac == NULL)
  85. bb_error_msg_and_die("cannot parse %s", selector);
  86. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  87. found_selector++;
  88. };
  89. selector = next;
  90. }
  91. if (found_selector == 0)
  92. bb_error_msg_and_die("no selectors found for %s", ch->ifname);
  93. #endif
  94. }
  95. static void prepend_new_eth_table(ethtable_t **clist, char *ifname, char *selector)
  96. {
  97. ethtable_t *ch;
  98. if (strlen(ifname) >= IFNAMSIZ)
  99. bb_error_msg_and_die("interface name '%s' too long", ifname);
  100. ch = xzalloc(sizeof(*ch));
  101. ch->ifname = xstrdup(ifname);
  102. nameif_parse_selector(ch, selector);
  103. ch->next = *clist;
  104. if (*clist)
  105. (*clist)->prev = ch;
  106. *clist = ch;
  107. }
  108. #if ENABLE_FEATURE_CLEAN_UP
  109. static void delete_eth_table(ethtable_t *ch)
  110. {
  111. free(ch->ifname);
  112. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  113. free(ch->bus_info);
  114. free(ch->driver);
  115. #endif
  116. free(ch->mac);
  117. free(ch);
  118. };
  119. #else
  120. void delete_eth_table(ethtable_t *ch);
  121. #endif
  122. int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  123. int nameif_main(int argc, char **argv)
  124. {
  125. ethtable_t *clist = NULL;
  126. FILE *ifh;
  127. const char *fname = "/etc/mactab";
  128. char *line;
  129. char *line_ptr;
  130. int linenum;
  131. int ctl_sk;
  132. ethtable_t *ch;
  133. if (1 & getopt32(argv, "sc:", &fname)) {
  134. openlog(applet_name, 0, LOG_LOCAL0);
  135. logmode = LOGMODE_SYSLOG;
  136. }
  137. argc -= optind;
  138. argv += optind;
  139. if (argc & 1)
  140. bb_show_usage();
  141. if (argc) {
  142. while (*argv) {
  143. char *ifname = xstrdup(*argv++);
  144. prepend_new_eth_table(&clist, ifname, *argv++);
  145. }
  146. } else {
  147. ifh = xfopen(fname, "r");
  148. while ((line = xmalloc_fgets(ifh)) != NULL) {
  149. char *next;
  150. line_ptr = skip_whitespace(line);
  151. if ((line_ptr[0] == '#') || (line_ptr[0] == '\n'))
  152. goto read_next_line;
  153. next = skip_non_whitespace(line_ptr);
  154. if (*next)
  155. *next++ = '\0';
  156. prepend_new_eth_table(&clist, line_ptr, next);
  157. read_next_line:
  158. free(line);
  159. }
  160. fclose(ifh);
  161. }
  162. ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);
  163. ifh = xfopen("/proc/net/dev", "r");
  164. linenum = 0;
  165. while (clist) {
  166. struct ifreq ifr;
  167. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  168. struct ethtool_drvinfo drvinfo;
  169. #endif
  170. line = xmalloc_fgets(ifh);
  171. if (line == NULL)
  172. break; /* Seems like we're done */
  173. if (linenum++ < 2 )
  174. goto next_line; /* Skip the first two lines */
  175. /* Find the current interface name and copy it to ifr.ifr_name */
  176. line_ptr = skip_whitespace(line);
  177. *strpbrk(line_ptr, " \t\n:") = '\0';
  178. memset(&ifr, 0, sizeof(struct ifreq));
  179. strncpy(ifr.ifr_name, line_ptr, sizeof(ifr.ifr_name));
  180. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  181. /* Check for driver etc. */
  182. memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo));
  183. drvinfo.cmd = ETHTOOL_GDRVINFO;
  184. ifr.ifr_data = (caddr_t) &drvinfo;
  185. /* Get driver and businfo first, so we have it in drvinfo */
  186. ioctl(ctl_sk, SIOCETHTOOL, &ifr);
  187. #endif
  188. ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
  189. /* Search the list for a matching device */
  190. for (ch = clist; ch; ch = ch->next) {
  191. #if ENABLE_FEATURE_NAMEIF_EXTENDED
  192. if (ch->bus_info && strcmp(ch->bus_info, drvinfo.bus_info) != 0)
  193. continue;
  194. if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0)
  195. continue;
  196. #endif
  197. if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0)
  198. continue;
  199. /* if we came here, all selectors have matched */
  200. goto found;
  201. }
  202. /* Nothing found for current interface */
  203. goto next_line;
  204. found:
  205. if (strcmp(ifr.ifr_name, ch->ifname) != 0) {
  206. strcpy(ifr.ifr_newname, ch->ifname);
  207. ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr,
  208. "cannot change ifname %s to %s",
  209. ifr.ifr_name, ch->ifname);
  210. }
  211. /* Remove list entry of renamed interface */
  212. if (ch->prev != NULL)
  213. ch->prev->next = ch->next;
  214. else
  215. clist = ch->next;
  216. if (ch->next != NULL)
  217. ch->next->prev = ch->prev;
  218. if (ENABLE_FEATURE_CLEAN_UP)
  219. delete_eth_table(ch);
  220. next_line:
  221. free(line);
  222. }
  223. if (ENABLE_FEATURE_CLEAN_UP) {
  224. for (ch = clist; ch; ch = ch->next)
  225. delete_eth_table(ch);
  226. fclose(ifh);
  227. };
  228. return 0;
  229. }