diff options
author | Denis Vlasenko | 2007-12-24 14:09:19 +0000 |
---|---|---|
committer | Denis Vlasenko | 2007-12-24 14:09:19 +0000 |
commit | f7be20e70c27b0bed505710393a99d1b6f821ff1 (patch) | |
tree | 151940c339bd35b64734053bb656488c9dbc3daa /networking/nameif.c | |
parent | fcfb5c04bbaa52ae7df5d45bc3ddadcc9e935fa1 (diff) | |
download | busybox-f7be20e70c27b0bed505710393a99d1b6f821ff1.zip busybox-f7be20e70c27b0bed505710393a99d1b6f821ff1.tar.gz |
nameif: extended matching (Nico Erfurth <masta@perlgolf.de>)
*: whitespace fixes
function old new delta
prepend_new_eth_table - 304 +304
nameif_main 620 684 +64
cc_macaddr 51 - -51
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/0 up/down: 368/-51) Total: 317 bytes
Diffstat (limited to 'networking/nameif.c')
-rw-r--r-- | networking/nameif.c | 230 |
1 files changed, 153 insertions, 77 deletions
diff --git a/networking/nameif.c b/networking/nameif.c index a951970..66376a5 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -13,7 +13,7 @@ #include <syslog.h> #include <net/if.h> #include <netinet/ether.h> - +#include <linux/sockios.h> /* Older versions of net/if.h do not appear to define IF_NAMESIZE. */ #ifndef IF_NAMESIZE @@ -34,138 +34,214 @@ #define ifr_newname ifr_ifru.ifru_slave #endif -typedef struct mactable_s { - struct mactable_s *next; - struct mactable_s *prev; +typedef struct ethtable_s { + struct ethtable_s *next; + struct ethtable_s *prev; char *ifname; struct ether_addr *mac; -} mactable_t; +#if ENABLE_FEATURE_NAMEIF_EXTENDED + char *bus_info; + char *driver; +#endif +} ethtable_t; + +#if ENABLE_FEATURE_NAMEIF_EXTENDED +/* Cut'n'paste from ethtool.h */ +#define ETHTOOL_BUSINFO_LEN 32 +/* these strings are set to whatever the driver author decides... */ +struct ethtool_drvinfo { + __u32 cmd; + char driver[32]; /* driver short name, "tulip", "eepro100" */ + char version[32]; /* driver version string */ + char fw_version[32]; /* firmware version string, if applicable */ + char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ + /* For PCI devices, use pci_dev->slot_name. */ + char reserved1[32]; + char reserved2[16]; + __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ + __u32 testinfo_len; + __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ + __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ +}; +#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ +#endif + -/* Check ascii str_macaddr, convert and copy to *mac */ -static struct ether_addr *cc_macaddr(const char *str_macaddr) +static void nameif_parse_selector(ethtable_t *ch, char *selector) { - struct ether_addr *lmac, *mac; + struct ether_addr *lmac; +#if ENABLE_FEATURE_NAMEIF_EXTENDED + int found_selector = 0; - lmac = ether_aton(str_macaddr); - if (lmac == NULL) - bb_error_msg_and_die("cannot parse MAC %s", str_macaddr); - mac = xmalloc(ETH_ALEN); - memcpy(mac, lmac, ETH_ALEN); + while (*selector) { + char *next; +#endif + selector = skip_whitespace(selector); +#if ENABLE_FEATURE_NAMEIF_EXTENDED + if (*selector == '\0') + break; + /* Search for the end .... */ + next = skip_non_whitespace(selector); + if (*next) + *next++ = '\0'; + /* Check for selectors, mac= is assumed */ + if (strncmp(selector, "bus=", 4) == 0) { + ch->bus_info = xstrdup(selector + 4); + found_selector++; + } else if (strncmp(selector, "driver=", 7) == 0) { + ch->driver = xstrdup(selector + 7); + found_selector++; + } else { +#endif + lmac = ether_aton(selector + (strncmp(selector, "mac=", 4) == 0 ? 4 : 0)); + /* Check ascii selector, convert and copy to *mac */ + if (lmac == NULL) + bb_error_msg_and_die("cannot parse %s", selector); + ch->mac = xmalloc(ETH_ALEN); + memcpy(ch->mac, lmac, ETH_ALEN); +#if ENABLE_FEATURE_NAMEIF_EXTENDED + found_selector++; + }; + selector = next; + } + if (found_selector == 0) + bb_error_msg_and_die("no selectors found for %s", ch->ifname); +#endif +} - return mac; +static void prepend_new_eth_table(ethtable_t **clist, char *ifname, char *selector) +{ + ethtable_t *ch; + if (strlen(ifname) >= IF_NAMESIZE) + bb_error_msg_and_die("interface name '%s' too long", ifname); + ch = xzalloc(sizeof(*ch)); + ch->ifname = ifname; + nameif_parse_selector(ch, selector); + ch->next = *clist; + if (*clist) + (*clist)->prev = ch; + *clist = ch; } int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int nameif_main(int argc, char **argv) { - mactable_t *clist = NULL; + ethtable_t *clist = NULL; FILE *ifh; const char *fname = "/etc/mactab"; char *line; + char *line_ptr; + int linenum; int ctl_sk; - int if_index = 1; - mactable_t *ch; + ethtable_t *ch; if (1 & getopt32(argv, "sc:", &fname)) { openlog(applet_name, 0, LOG_LOCAL0); logmode = LOGMODE_SYSLOG; } + argc -= optind; + argv += optind; - if ((argc - optind) & 1) + if (argc & 1) bb_show_usage(); - if (optind < argc) { - char **a = argv + optind; - - while (*a) { - if (strlen(*a) > IF_NAMESIZE) - bb_error_msg_and_die("interface name '%s' " - "too long", *a); - ch = xzalloc(sizeof(mactable_t)); - ch->ifname = xstrdup(*a++); - ch->mac = cc_macaddr(*a++); - if (clist) - clist->prev = ch; - ch->next = clist; - clist = ch; + if (argc) { + while (*argv) { + char *ifname = xstrdup(*argv++); + prepend_new_eth_table(&clist, ifname, *argv++); } } else { ifh = xfopen(fname, "r"); - while ((line = xmalloc_fgets(ifh)) != NULL) { - char *line_ptr; - size_t name_length; + char *next; - line_ptr = line + strspn(line, " \t"); + line_ptr = skip_whitespace(line); if ((line_ptr[0] == '#') || (line_ptr[0] == '\n')) { free(line); continue; } - name_length = strcspn(line_ptr, " \t"); - ch = xzalloc(sizeof(mactable_t)); - ch->ifname = xstrndup(line_ptr, name_length); - if (name_length > IF_NAMESIZE) - bb_error_msg_and_die("interface name '%s' " - "too long", ch->ifname); - line_ptr += name_length; - line_ptr += strspn(line_ptr, " \t"); - name_length = strspn(line_ptr, "0123456789ABCDEFabcdef:"); - line_ptr[name_length] = '\0'; - ch->mac = cc_macaddr(line_ptr); - if (clist) - clist->prev = ch; - ch->next = clist; - clist = ch; + next = skip_non_whitespace(line_ptr); + if (*next) + *next++ = '\0'; + prepend_new_eth_table(&clist, line_ptr, next); free(line); } fclose(ifh); } ctl_sk = xsocket(PF_INET, SOCK_DGRAM, 0); + ifh = xfopen("/proc/net/dev", "r"); + linenum = 0; while (clist) { struct ifreq ifr; +#if ENABLE_FEATURE_NAMEIF_EXTENDED + struct ethtool_drvinfo drvinfo; +#endif - memset(&ifr, 0, sizeof(struct ifreq)); - if_index++; - ifr.ifr_ifindex = if_index; - - /* Get ifname by index or die */ - if (ioctl(ctl_sk, SIOCGIFNAME, &ifr)) - break; - - /* Has this device hwaddr? */ - if (ioctl(ctl_sk, SIOCGIFHWADDR, &ifr)) - continue; + line = xmalloc_fgets(ifh); + if (line == NULL) + break; /* Seems like we're done */ + if (linenum++ < 2 ) + goto next_line; /* Skip the first two lines */ - /* Search for mac like in ifr.ifr_hwaddr.sa_data */ - for (ch = clist; ch; ch = ch->next) - if (!memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN)) - break; + /* Find the current interface name and copy it to ifr.ifr_name */ + line_ptr = skip_whitespace(line); + *skip_non_whitespace(line_ptr) = '\0'; - /* Nothing found for current ifr.ifr_hwaddr.sa_data */ - if (ch == NULL) - continue; + memset(&ifr, 0, sizeof(struct ifreq)); + strncpy(ifr.ifr_name, line_ptr, sizeof(ifr.ifr_name)); + +#if ENABLE_FEATURE_NAMEIF_EXTENDED + /* Check for driver etc. */ + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + drvinfo.cmd = ETHTOOL_GDRVINFO; + ifr.ifr_data = (caddr_t) &drvinfo; + /* Get driver and businfo first, so we have it in drvinfo */ + ioctl(ctl_sk, SIOCETHTOOL, &ifr); +#endif + ioctl(ctl_sk, SIOCGIFHWADDR, &ifr); - strcpy(ifr.ifr_newname, ch->ifname); - ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, + /* Search the list for a matching device */ + for (ch = clist; ch; ch = ch->next) { +#if ENABLE_FEATURE_NAMEIF_EXTENDED + if (ch->bus_info && strcmp(ch->bus_info, drvinfo.bus_info) != 0) + continue; + if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0) + continue; +#endif + if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) + continue; + /* if we came here, all selectors have matched */ + goto found; + } + /* Nothing found for current interface */ + goto next_line; + found: + if (strcmp(ifr.ifr_name, ch->ifname) != 0) { + strcpy(ifr.ifr_newname, ch->ifname); + ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, "cannot change ifname %s to %s", ifr.ifr_name, ch->ifname); - + } /* Remove list entry of renamed interface */ - if (ch->prev != NULL) { - (ch->prev)->next = ch->next; - } else { + if (ch->prev != NULL) + ch->prev->next = ch->next; + else clist = ch->next; - } if (ch->next != NULL) - (ch->next)->prev = ch->prev; + ch->next->prev = ch->prev; if (ENABLE_FEATURE_CLEAN_UP) { free(ch->ifname); free(ch->mac); free(ch); } + next_line: + free(line); } + if (ENABLE_FEATURE_CLEAN_UP) { + fclose(ifh); + }; return 0; } |