source: MondoRescue/branches/3.3/mindi-busybox/networking/nameif.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 9.7 KB
RevLine 
[1765]1/* vi: set sw=4 ts=4: */
[821]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>
[2725]7 * Glenn McGrath
8 * Extended matching support 2008 by Nico Erfurth <masta@perlgolf.de>
[821]9 *
[2725]10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
[821]11 */
12
[3232]13//config:config NAMEIF
14//config: bool "nameif"
15//config: default y
16//config: select PLATFORM_LINUX
17//config: select FEATURE_SYSLOG
18//config: help
19//config: nameif is used to rename network interface by its MAC address.
20//config: Renamed interfaces MUST be in the down state.
21//config: It is possible to use a file (default: /etc/mactab)
22//config: with list of new interface names and MACs.
23//config: Maximum interface name length: IFNAMSIZ = 16
24//config: File fields are separated by space or tab.
25//config: File format:
26//config: # Comment
27//config: new_interface_name XX:XX:XX:XX:XX:XX
28//config:
29//config:config FEATURE_NAMEIF_EXTENDED
30//config: bool "Extended nameif"
31//config: default y
32//config: depends on NAMEIF
33//config: help
34//config: This extends the nameif syntax to support the bus_info, driver,
35//config: phyaddr selectors. The syntax is compatible to the normal nameif.
36//config: File format:
37//config: new_interface_name driver=asix bus=usb-0000:00:08.2-3
38//config: new_interface_name bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5
39//config: new_interface_name phy_address=2 00:80:C8:38:91:B5
40//config: new_interface_name mac=00:80:C8:38:91:B5
41//config: new_interface_name 00:80:C8:38:91:B5
42
43//usage:#define nameif_trivial_usage
44//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED(
45//usage: "[-s] [-c FILE] [IFNAME HWADDR]..."
46//usage: )
47//usage: IF_FEATURE_NAMEIF_EXTENDED(
48//usage: "[-s] [-c FILE] [IFNAME SELECTOR]..."
49//usage: )
50//usage:#define nameif_full_usage "\n\n"
51//usage: "Rename network interface while it in the down state."
52//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED(
53//usage: "\nThe device with address HWADDR is renamed to IFACE."
54//usage: )
55//usage: IF_FEATURE_NAMEIF_EXTENDED(
56//usage: "\nThe device matched by SELECTOR is renamed to IFACE."
57//usage: "\nSELECTOR can be a combination of:"
58//usage: "\n driver=STRING"
59//usage: "\n bus=STRING"
60//usage: "\n phy_address=NUM"
61//usage: "\n [mac=]XX:XX:XX:XX:XX:XX"
62//usage: )
63//usage: "\n"
64//usage: "\n -c FILE Configuration file (default: /etc/mactab)"
65//usage: "\n -s Log to syslog"
66//usage:
67//usage:#define nameif_example_usage
68//usage: "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n"
69//usage: " or\n"
70//usage: "$ nameif -c /etc/my_mactab_file\n"
71
[1765]72#include "libbb.h"
73#include <syslog.h>
[821]74#include <net/if.h>
75#include <netinet/ether.h>
[2725]76#include <linux/sockios.h>
[821]77
[2725]78#ifndef IFNAMSIZ
79#define IFNAMSIZ 16
[821]80#endif
81
[2725]82/* Taken from linux/sockios.h */
83#define SIOCSIFNAME 0x8923 /* set interface name */
[821]84
85/* Octets in one Ethernet addr, from <linux/if_ether.h> */
[2725]86#define ETH_ALEN 6
[821]87
88#ifndef ifr_newname
89#define ifr_newname ifr_ifru.ifru_slave
90#endif
91
[2725]92typedef struct ethtable_s {
93 struct ethtable_s *next;
94 struct ethtable_s *prev;
[821]95 char *ifname;
96 struct ether_addr *mac;
[2725]97#if ENABLE_FEATURE_NAMEIF_EXTENDED
98 char *bus_info;
99 char *driver;
[3232]100 int32_t phy_address;
[2725]101#endif
102} ethtable_t;
[821]103
[2725]104#if ENABLE_FEATURE_NAMEIF_EXTENDED
105/* Cut'n'paste from ethtool.h */
106#define ETHTOOL_BUSINFO_LEN 32
107/* these strings are set to whatever the driver author decides... */
108struct ethtool_drvinfo {
109 uint32_t cmd;
110 char driver[32]; /* driver short name, "tulip", "eepro100" */
111 char version[32]; /* driver version string */
112 char fw_version[32]; /* firmware version string, if applicable */
113 char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
114 /* For PCI devices, use pci_dev->slot_name. */
115 char reserved1[32];
116 char reserved2[16];
117 uint32_t n_stats; /* number of u64's from ETHTOOL_GSTATS */
118 uint32_t testinfo_len;
119 uint32_t eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */
120 uint32_t regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */
121};
[3232]122
123struct ethtool_cmd {
124 uint32_t cmd;
125 uint32_t supported; /* Features this interface supports */
126 uint32_t advertising; /* Features this interface advertises */
127 uint16_t speed; /* The forced speed, 10Mb, 100Mb, gigabit */
128 uint8_t duplex; /* Duplex, half or full */
129 uint8_t port; /* Which connector port */
130 uint8_t phy_address;
131 uint8_t transceiver; /* Which transceiver to use */
132 uint8_t autoneg; /* Enable or disable autonegotiation */
133 uint32_t maxtxpkt; /* Tx pkts before generating tx int */
134 uint32_t maxrxpkt; /* Rx pkts before generating rx int */
135 uint16_t speed_hi;
136 uint16_t reserved2;
137 uint32_t reserved[3];
138};
139
140#define ETHTOOL_GSET 0x00000001 /* Get settings. */
[2725]141#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */
142#endif
143
144
145static void nameif_parse_selector(ethtable_t *ch, char *selector)
[821]146{
[2725]147 struct ether_addr *lmac;
148#if ENABLE_FEATURE_NAMEIF_EXTENDED
149 int found_selector = 0;
[821]150
[2725]151 while (*selector) {
152 char *next;
153#endif
154 selector = skip_whitespace(selector);
155#if ENABLE_FEATURE_NAMEIF_EXTENDED
[3232]156 ch->phy_address = -1;
[2725]157 if (*selector == '\0')
158 break;
159 /* Search for the end .... */
160 next = skip_non_whitespace(selector);
161 if (*next)
162 *next++ = '\0';
163 /* Check for selectors, mac= is assumed */
[3621]164 if (is_prefixed_with(selector, "bus=")) {
[2725]165 ch->bus_info = xstrdup(selector + 4);
166 found_selector++;
[3621]167 } else if (is_prefixed_with(selector, "driver=")) {
[2725]168 ch->driver = xstrdup(selector + 7);
169 found_selector++;
[3621]170 } else if (is_prefixed_with(selector, "phyaddr=")) {
[3232]171 ch->phy_address = xatoi_positive(selector + 8);
172 found_selector++;
[2725]173 } else {
174#endif
175 lmac = xmalloc(ETH_ALEN);
[3621]176 ch->mac = ether_aton_r(selector + (is_prefixed_with(selector, "mac=") ? 4 : 0), lmac);
[2725]177 if (ch->mac == NULL)
178 bb_error_msg_and_die("can't parse %s", selector);
179#if ENABLE_FEATURE_NAMEIF_EXTENDED
180 found_selector++;
181 };
182 selector = next;
183 }
184 if (found_selector == 0)
185 bb_error_msg_and_die("no selectors found for %s", ch->ifname);
186#endif
187}
[821]188
[2725]189static void prepend_new_eth_table(ethtable_t **clist, char *ifname, char *selector)
190{
191 ethtable_t *ch;
192 if (strlen(ifname) >= IFNAMSIZ)
193 bb_error_msg_and_die("interface name '%s' too long", ifname);
194 ch = xzalloc(sizeof(*ch));
195 ch->ifname = xstrdup(ifname);
196 nameif_parse_selector(ch, selector);
197 ch->next = *clist;
198 if (*clist)
199 (*clist)->prev = ch;
200 *clist = ch;
[821]201}
202
[2725]203#if ENABLE_FEATURE_CLEAN_UP
204static void delete_eth_table(ethtable_t *ch)
205{
206 free(ch->ifname);
207#if ENABLE_FEATURE_NAMEIF_EXTENDED
208 free(ch->bus_info);
209 free(ch->driver);
210#endif
211 free(ch->mac);
212 free(ch);
213};
214#else
215void delete_eth_table(ethtable_t *ch);
216#endif
217
218int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
[3232]219int nameif_main(int argc UNUSED_PARAM, char **argv)
[821]220{
[2725]221 ethtable_t *clist = NULL;
[821]222 const char *fname = "/etc/mactab";
223 int ctl_sk;
[2725]224 ethtable_t *ch;
225 parser_t *parser;
226 char *token[2];
[821]227
[1765]228 if (1 & getopt32(argv, "sc:", &fname)) {
229 openlog(applet_name, 0, LOG_LOCAL0);
[2725]230 /* Why not just "="? I assume logging to stderr
231 * can't hurt. 2>/dev/null if you don't like it: */
232 logmode |= LOGMODE_SYSLOG;
[1765]233 }
[2725]234 argv += optind;
[821]235
[3232]236 if (argv[0]) {
237 do {
238 if (!argv[1])
239 bb_show_usage();
240 prepend_new_eth_table(&clist, argv[0], argv[1]);
241 argv += 2;
242 } while (*argv);
[821]243 } else {
[2725]244 parser = config_open(fname);
245 while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL))
246 prepend_new_eth_table(&clist, token[0], token[1]);
247 config_close(parser);
[821]248 }
249
[1765]250 ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0);
[2725]251 parser = config_open2("/proc/net/dev", xfopen_for_read);
[821]252
[2725]253 while (clist && config_read(parser, token, 2, 2, "\0: \t", PARSE_NORMAL)) {
[821]254 struct ifreq ifr;
[2725]255#if ENABLE_FEATURE_NAMEIF_EXTENDED
256 struct ethtool_drvinfo drvinfo;
[3232]257 struct ethtool_cmd eth_settings;
[2725]258#endif
[3232]259 if (parser->lineno <= 2)
[2725]260 continue; /* Skip the first two lines */
[821]261
[2725]262 /* Find the current interface name and copy it to ifr.ifr_name */
[821]263 memset(&ifr, 0, sizeof(struct ifreq));
[2725]264 strncpy_IFNAMSIZ(ifr.ifr_name, token[0]);
[821]265
[2725]266#if ENABLE_FEATURE_NAMEIF_EXTENDED
[3232]267 /* Check for phy address */
268 memset(&eth_settings, 0, sizeof(eth_settings));
269 eth_settings.cmd = ETHTOOL_GSET;
270 ifr.ifr_data = (caddr_t) &eth_settings;
271 ioctl(ctl_sk, SIOCETHTOOL, &ifr);
272
[2725]273 /* Check for driver etc. */
[3232]274 memset(&drvinfo, 0, sizeof(drvinfo));
[2725]275 drvinfo.cmd = ETHTOOL_GDRVINFO;
276 ifr.ifr_data = (caddr_t) &drvinfo;
277 /* Get driver and businfo first, so we have it in drvinfo */
278 ioctl(ctl_sk, SIOCETHTOOL, &ifr);
279#endif
280 ioctl(ctl_sk, SIOCGIFHWADDR, &ifr);
281
282 /* Search the list for a matching device */
283 for (ch = clist; ch; ch = ch->next) {
284#if ENABLE_FEATURE_NAMEIF_EXTENDED
285 if (ch->bus_info && strcmp(ch->bus_info, drvinfo.bus_info) != 0)
286 continue;
287 if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0)
288 continue;
[3232]289 if (ch->phy_address != -1 && ch->phy_address != eth_settings.phy_address)
290 continue;
[2725]291#endif
292 if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0)
293 continue;
294 /* if we came here, all selectors have matched */
[3621]295 goto found;
[2725]296 }
297 /* Nothing found for current interface */
[3621]298 continue;
299 found:
[2725]300 if (strcmp(ifr.ifr_name, ch->ifname) != 0) {
301 strcpy(ifr.ifr_newname, ch->ifname);
302 ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr,
303 "can't change ifname %s to %s",
[1765]304 ifr.ifr_name, ch->ifname);
[2725]305 }
[821]306 /* Remove list entry of renamed interface */
[2725]307 if (ch->prev != NULL)
308 ch->prev->next = ch->next;
309 else
[821]310 clist = ch->next;
311 if (ch->next != NULL)
[2725]312 ch->next->prev = ch->prev;
313 if (ENABLE_FEATURE_CLEAN_UP)
314 delete_eth_table(ch);
[3621]315 } /* while */
316
[2725]317 if (ENABLE_FEATURE_CLEAN_UP) {
[3621]318 ethtable_t *next;
319 for (ch = clist; ch; ch = next) {
320 next = ch->next;
[2725]321 delete_eth_table(ch);
[3621]322 }
[2725]323 config_close(parser);
324 };
[821]325
326 return 0;
327}
Note: See TracBrowser for help on using the repository browser.