nameif.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * nameif.c - Naming Interfaces based on MAC address for busybox.
  3. *
  4. * Written 2000 by Andi Kleen.
  5. * Busybox port 2002 by Nick Fedchik <nick@fedchik.org.ua>
  6. * Glenn McGrath <bug1@iinet.net.au>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  21. * 02111-1307 USA
  22. *
  23. */
  24. #include <sys/syslog.h>
  25. #include <sys/socket.h>
  26. #include <sys/ioctl.h>
  27. #include <errno.h>
  28. #include <getopt.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <net/if.h>
  32. #include <netinet/ether.h>
  33. #include "busybox.h"
  34. /* Older versions of net/if.h do not appear to define IF_NAMESIZE. */
  35. #ifndef IF_NAMESIZE
  36. # ifdef IFNAMSIZ
  37. # define IF_NAMESIZE IFNAMSIZ
  38. # else
  39. # define IF_NAMESIZE 16
  40. # endif
  41. #endif
  42. /* take from linux/sockios.h */
  43. #define SIOCSIFNAME 0x8923 /* set interface name */
  44. /* Octets in one Ethernet addr, from <linux/if_ether.h> */
  45. #define ETH_ALEN 6
  46. #ifndef ifr_newname
  47. #define ifr_newname ifr_ifru.ifru_slave
  48. #endif
  49. typedef struct mactable_s {
  50. struct mactable_s *next;
  51. struct mactable_s *prev;
  52. char *ifname;
  53. struct ether_addr *mac;
  54. } mactable_t;
  55. static unsigned char use_syslog;
  56. static void serror(const char *s, ...) __attribute__ ((noreturn));
  57. static void serror(const char *s, ...)
  58. {
  59. va_list ap;
  60. va_start(ap, s);
  61. if (use_syslog) {
  62. openlog(bb_applet_name, 0, LOG_LOCAL0);
  63. vsyslog(LOG_ERR, s, ap);
  64. closelog();
  65. } else {
  66. bb_verror_msg(s, ap);
  67. putc('\n', stderr);
  68. }
  69. va_end(ap);
  70. exit(EXIT_FAILURE);
  71. }
  72. /* Check ascii str_macaddr, convert and copy to *mac */
  73. static struct ether_addr *cc_macaddr(char *str_macaddr)
  74. {
  75. struct ether_addr *lmac, *mac;
  76. lmac = ether_aton(str_macaddr);
  77. if (lmac == NULL)
  78. serror("cannot parse MAC %s", str_macaddr);
  79. mac = xmalloc(ETH_ALEN);
  80. memcpy(mac, lmac, ETH_ALEN);
  81. return mac;
  82. }
  83. int nameif_main(int argc, char **argv)
  84. {
  85. mactable_t *clist = NULL;
  86. FILE *ifh;
  87. const char *fname = "/etc/mactab";
  88. char *line;
  89. int ctl_sk;
  90. int opt;
  91. int if_index = 1;
  92. mactable_t *ch;
  93. while ((opt = getopt(argc, argv, "c:s")) != -1) {
  94. switch (opt) {
  95. case 'c':
  96. fname = optarg;
  97. break;
  98. case 's':
  99. use_syslog = 1;
  100. break;
  101. default:
  102. bb_show_usage();
  103. }
  104. }
  105. if ((argc - optind) & 1)
  106. bb_show_usage();
  107. if (optind < argc) {
  108. char **a = argv + optind;
  109. while (*a) {
  110. if (strlen(*a) > IF_NAMESIZE)
  111. serror("interface name `%s' too long", *a);
  112. ch = xcalloc(1, sizeof(mactable_t));
  113. ch->ifname = bb_xstrdup(*a++);
  114. ch->mac = cc_macaddr(*a++);
  115. if (clist)
  116. clist->prev = ch;
  117. ch->next = clist;
  118. clist = ch;
  119. }
  120. } else {
  121. ifh = bb_xfopen(fname, "r");
  122. while ((line = bb_get_line_from_file(ifh)) != NULL) {
  123. char *line_ptr;
  124. size_t name_length;
  125. line_ptr = line + strspn(line, " \t");
  126. if ((line_ptr[0] == '#') || (line_ptr[0] == '\n'))
  127. continue;
  128. name_length = strcspn(line_ptr, " \t");
  129. ch = xcalloc(1, sizeof(mactable_t));
  130. ch->ifname = bb_xstrndup(line_ptr, name_length);
  131. if (name_length > IF_NAMESIZE)
  132. serror("interface name `%s' too long", ch->ifname);
  133. line_ptr += name_length;
  134. line_ptr += strspn(line_ptr, " \t");
  135. name_length = strspn(line_ptr, "0123456789ABCDEFabcdef:");
  136. line_ptr[name_length] = '\0';
  137. ch->mac = cc_macaddr(line_ptr);
  138. if (clist)
  139. clist->prev = ch;
  140. ch->next = clist;
  141. clist = ch;
  142. free(line);
  143. }
  144. fclose(ifh);
  145. }
  146. if ((ctl_sk = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
  147. serror("socket: %m");
  148. while (clist) {
  149. struct ifreq ifr;
  150. bzero(&ifr, sizeof(struct ifreq));
  151. if_index++;
  152. ifr.ifr_ifindex = if_index;
  153. /* Get ifname by index or die */
  154. if (ioctl(ctl_sk, SIOCGIFNAME, &ifr))
  155. break;
  156. /* Has this device hwaddr? */
  157. if (ioctl(ctl_sk, SIOCGIFHWADDR, &ifr))
  158. continue;
  159. /* Search for mac like in ifr.ifr_hwaddr.sa_data */
  160. for (ch = clist; ch; ch = ch->next)
  161. if (!memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN))
  162. break;
  163. /* Nothing found for current ifr.ifr_hwaddr.sa_data */
  164. if (ch == NULL)
  165. continue;
  166. strcpy(ifr.ifr_newname, ch->ifname);
  167. if (ioctl(ctl_sk, SIOCSIFNAME, &ifr) < 0)
  168. serror("cannot change ifname %s to %s: %m",
  169. ifr.ifr_name, ch->ifname);
  170. /* Remove list entry of renamed interface */
  171. if (ch->prev != NULL) {
  172. (ch->prev)->next = ch->next;
  173. } else {
  174. clist = ch->next;
  175. }
  176. if (ch->next != NULL)
  177. (ch->next)->prev = ch->prev;
  178. #ifdef CONFIG_FEATURE_CLEAN_UP
  179. free(ch->ifname);
  180. free(ch->mac);
  181. free(ch);
  182. #endif
  183. }
  184. return 0;
  185. }