diff options
-rw-r--r-- | networking/ifenslave.c | 466 |
1 files changed, 227 insertions, 239 deletions
diff --git a/networking/ifenslave.c b/networking/ifenslave.c index 071cac722..44839868a 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c @@ -133,19 +133,7 @@ struct globals { } while (0) -static void get_drv_info(char *master_ifname); -static int get_if_settings(char *ifname, struct dev_data *dd); -static int get_slave_flags(char *slave_ifname); -static int set_hwaddr(char *ifname, struct sockaddr *hwaddr); -static int set_mtu(char *ifname, int mtu); -static int set_if_flags(char *ifname, int flags); -static int set_if_up(char *ifname, int flags); -static int set_if_down(char *ifname, int flags); -static int clear_if_addr(char *ifname); -static int set_if_addr(char *master_ifname, char *slave_ifname); -static void change_active(char *master_ifname, char *slave_ifname); -static int enslave(char *master_ifname, char *slave_ifname); -static int release(char *master_ifname, char *slave_ifname); +/* NOINLINEs are placed where it results in smaller code (gcc 4.3.1) */ static void strncpy_IFNAMSIZ(char *dst, const char *src) { @@ -163,173 +151,109 @@ static int set_ifrname_and_do_ioctl(unsigned request, struct ifreq *ifr, const c return ioctl_on_skfd(request, ifr); } -int ifenslave_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv) +static int get_if_settings(char *ifname, struct dev_data *dd) { - char *master_ifname, *slave_ifname; - int rv; int res; - unsigned opt; - enum { - OPT_c = (1 << 0), - OPT_d = (1 << 1), - OPT_f = (1 << 2), - }; -#if ENABLE_GETOPT_LONG - static const char ifenslave_longopts[] ALIGN1 = - "change-active\0" No_argument "c" - "detach\0" No_argument "d" - "force\0" No_argument "f" - ; - - applet_long_options = ifenslave_longopts; -#endif - INIT_G(); - opt = getopt32(argv, "cdf"); - argv += optind; - if (opt & (opt-1)) /* options check */ - bb_show_usage(); - - master_ifname = *argv++; + res = set_ifrname_and_do_ioctl(SIOCGIFMTU, &dd->mtu, ifname); + res |= set_ifrname_and_do_ioctl(SIOCGIFFLAGS, &dd->flags, ifname); + res |= set_ifrname_and_do_ioctl(SIOCGIFHWADDR, &dd->hwaddr, ifname); - /* No interface names - show all interfaces. */ - if (!master_ifname) { - display_interfaces(NULL); - return EXIT_SUCCESS; - } + return res; +} - /* Open a basic socket */ - xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), skfd); +static int get_slave_flags(char *slave_ifname) +{ + return set_ifrname_and_do_ioctl(SIOCGIFFLAGS, &slave.flags, slave_ifname); +} - /* Exchange abi version with bonding module */ - get_drv_info(master_ifname); +static int set_hwaddr(char *ifname, struct sockaddr *hwaddr) +{ + struct ifreq ifr; - slave_ifname = *argv++; - if (!slave_ifname) { - if (opt & (OPT_d|OPT_c)) { - /* --change or --detach, and no slaves given - - * show all interfaces. */ - display_interfaces(slave_ifname /* == NULL */); - return 2; /* why 2? */ - } - /* A single arg means show the - * configuration for this interface - */ - display_interfaces(master_ifname); - return EXIT_SUCCESS; - } + memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(*hwaddr)); + return set_ifrname_and_do_ioctl(SIOCSIFHWADDR, &ifr, ifname); +} - res = get_if_settings(master_ifname, &master); - if (res) { - /* Probably a good reason not to go on */ - bb_perror_msg_and_die("%s: can't get settings", master_ifname); - } +static int set_mtu(char *ifname, int mtu) +{ + struct ifreq ifr; - /* check if master is indeed a master; - * if not then fail any operation - */ - if (!(master.flags.ifr_flags & IFF_MASTER)) - bb_error_msg_and_die("%s is not a master", master_ifname); + ifr.ifr_mtu = mtu; + return set_ifrname_and_do_ioctl(SIOCSIFMTU, &ifr, ifname); +} - /* check if master is up; if not then fail any operation */ - if (!(master.flags.ifr_flags & IFF_UP)) - bb_error_msg_and_die("%s is not up", master_ifname); +static int set_if_flags(char *ifname, int flags) +{ + struct ifreq ifr; - /* No opts: neither -c[hange] nor -d[etach] -> it's "enslave" then; - * and -f[orce] is not there too */ - if (!opt) { - /* The family '1' is ARPHRD_ETHER for ethernet. */ - if (master.hwaddr.ifr_hwaddr.sa_family != 1) { - bb_error_msg_and_die( - "%s is not ethernet-like (-f overrides)", - master_ifname); - } - } + ifr.ifr_flags = flags; + return set_ifrname_and_do_ioctl(SIOCSIFFLAGS, &ifr, ifname); +} - /* Accepts only one slave */ - if (opt & OPT_c) { - /* change active slave */ - if (get_slave_flags(slave_ifname)) { - bb_perror_msg_and_die( - "%s: can't get flags", slave_ifname); - } - change_active(master_ifname, slave_ifname); - return EXIT_SUCCESS; - } +static int set_if_up(char *ifname, int flags) +{ + int res = set_if_flags(ifname, flags | IFF_UP); + if (res) + bb_perror_msg("%s: can't up", ifname); + return res; +} - /* Accept multiple slaves */ - res = 0; - do { - if (opt & OPT_d) { - /* detach a slave interface from the master */ - rv = get_slave_flags(slave_ifname); - if (rv) { - /* Can't work with this slave, */ - /* remember the error and skip it */ - bb_perror_msg( - "skipping %s: can't get flags", - slave_ifname); - res = rv; - continue; - } - rv = release(master_ifname, slave_ifname); - if (rv) { - bb_perror_msg( - "master %s, slave %s: " - "can't release", - master_ifname, slave_ifname); - res = rv; - } - } else { - /* attach a slave interface to the master */ - rv = get_if_settings(slave_ifname, &slave); - if (rv) { - /* Can't work with this slave, */ - /* remember the error and skip it */ - bb_perror_msg( - "skipping %s: can't get settings", - slave_ifname); - res = rv; - continue; - } - rv = enslave(master_ifname, slave_ifname); - if (rv) { - bb_perror_msg( - "master %s, slave %s: " - "can't enslave", - master_ifname, slave_ifname); - res = rv; - } - } - } while ((slave_ifname = *argv++) != NULL); +static int set_if_down(char *ifname, int flags) +{ + int res = set_if_flags(ifname, flags & ~IFF_UP); + if (res) + bb_perror_msg("%s: can't down", ifname); + return res; +} - if (ENABLE_FEATURE_CLEAN_UP) { - close(skfd); - } +static int clear_if_addr(char *ifname) +{ + struct ifreq ifr; - return res; + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); + return set_ifrname_and_do_ioctl(SIOCSIFADDR, &ifr, ifname); } -static void get_drv_info(char *master_ifname) +static int set_if_addr(char *master_ifname, char *slave_ifname) { +#if (SIOCGIFADDR | SIOCSIFADDR \ + | SIOCGIFDSTADDR | SIOCSIFDSTADDR \ + | SIOCGIFBRDADDR | SIOCSIFBRDADDR \ + | SIOCGIFNETMASK | SIOCSIFNETMASK) <= 0xffff +#define INT uint16_t +#else +#define INT int +#endif + static const struct { + INT g_ioctl; + INT s_ioctl; + } ifra[] = { + { SIOCGIFADDR, SIOCSIFADDR }, + { SIOCGIFDSTADDR, SIOCSIFDSTADDR }, + { SIOCGIFBRDADDR, SIOCSIFBRDADDR }, + { SIOCGIFNETMASK, SIOCSIFNETMASK }, + }; + struct ifreq ifr; - struct ethtool_drvinfo info; + int res; + unsigned i; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_data = (caddr_t)&info; - info.cmd = ETHTOOL_GDRVINFO; - strncpy(info.driver, "ifenslave", 32); - snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); - if (set_ifrname_and_do_ioctl(SIOCETHTOOL, &ifr, master_ifname) < 0) { - if (errno == EOPNOTSUPP) - return; - bb_perror_msg_and_die("%s: SIOCETHTOOL error", master_ifname); + for (i = 0; i < ARRAY_SIZE(ifra); i++) { + res = set_ifrname_and_do_ioctl(ifra[i].g_ioctl, &ifr, master_ifname); + if (res < 0) { + ifr.ifr_addr.sa_family = AF_INET; + memset(ifr.ifr_addr.sa_data, 0, + sizeof(ifr.ifr_addr.sa_data)); + } + + res = set_ifrname_and_do_ioctl(ifra[i].s_ioctl, &ifr, slave_ifname); + if (res < 0) + return res; } - abi_ver = bb_strtou(info.fw_version, NULL, 0); - if (errno) - bb_error_msg_and_die("%s: SIOCETHTOOL error", master_ifname); + return 0; } static void change_active(char *master_ifname, char *slave_ifname) @@ -353,7 +277,7 @@ static void change_active(char *master_ifname, char *slave_ifname) } } -static int enslave(char *master_ifname, char *slave_ifname) +static NOINLINE int enslave(char *master_ifname, char *slave_ifname) { struct ifreq ifr; int res; @@ -502,107 +426,171 @@ static int release(char *master_ifname, char *slave_ifname) return res; } -static int get_if_settings(char *ifname, struct dev_data *dd) +static NOINLINE void get_drv_info(char *master_ifname) { - int res; + struct ifreq ifr; + struct ethtool_drvinfo info; - res = set_ifrname_and_do_ioctl(SIOCGIFMTU, &dd->mtu, ifname); - res |= set_ifrname_and_do_ioctl(SIOCGIFFLAGS, &dd->flags, ifname); - res |= set_ifrname_and_do_ioctl(SIOCGIFHWADDR, &dd->hwaddr, ifname); + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_data = (caddr_t)&info; + info.cmd = ETHTOOL_GDRVINFO; + strncpy(info.driver, "ifenslave", 32); + snprintf(info.fw_version, 32, "%d", BOND_ABI_VERSION); + if (set_ifrname_and_do_ioctl(SIOCETHTOOL, &ifr, master_ifname) < 0) { + if (errno == EOPNOTSUPP) + return; + bb_perror_msg_and_die("%s: SIOCETHTOOL error", master_ifname); + } - return res; + abi_ver = bb_strtou(info.fw_version, NULL, 0); + if (errno) + bb_error_msg_and_die("%s: SIOCETHTOOL error", master_ifname); } -static int get_slave_flags(char *slave_ifname) +int ifenslave_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ifenslave_main(int argc ATTRIBUTE_UNUSED, char **argv) { - return set_ifrname_and_do_ioctl(SIOCGIFFLAGS, &slave.flags, slave_ifname); -} + char *master_ifname, *slave_ifname; + int rv; + int res; + unsigned opt; + enum { + OPT_c = (1 << 0), + OPT_d = (1 << 1), + OPT_f = (1 << 2), + }; +#if ENABLE_GETOPT_LONG + static const char ifenslave_longopts[] ALIGN1 = + "change-active\0" No_argument "c" + "detach\0" No_argument "d" + "force\0" No_argument "f" + ; -static int set_hwaddr(char *ifname, struct sockaddr *hwaddr) -{ - struct ifreq ifr; + applet_long_options = ifenslave_longopts; +#endif + INIT_G(); - memcpy(&(ifr.ifr_hwaddr), hwaddr, sizeof(*hwaddr)); - return set_ifrname_and_do_ioctl(SIOCSIFHWADDR, &ifr, ifname); -} + opt = getopt32(argv, "cdf"); + argv += optind; + if (opt & (opt-1)) /* options check */ + bb_show_usage(); -static int set_mtu(char *ifname, int mtu) -{ - struct ifreq ifr; + master_ifname = *argv++; - ifr.ifr_mtu = mtu; - return set_ifrname_and_do_ioctl(SIOCSIFMTU, &ifr, ifname); -} + /* No interface names - show all interfaces. */ + if (!master_ifname) { + display_interfaces(NULL); + return EXIT_SUCCESS; + } -static int set_if_flags(char *ifname, int flags) -{ - struct ifreq ifr; + /* Open a basic socket */ + xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), skfd); - ifr.ifr_flags = flags; - return set_ifrname_and_do_ioctl(SIOCSIFFLAGS, &ifr, ifname); -} + /* Exchange abi version with bonding module */ + get_drv_info(master_ifname); -static int set_if_up(char *ifname, int flags) -{ - int res = set_if_flags(ifname, flags | IFF_UP); - if (res) - bb_perror_msg("%s: can't up", ifname); - return res; -} + slave_ifname = *argv++; + if (!slave_ifname) { + if (opt & (OPT_d|OPT_c)) { + /* --change or --detach, and no slaves given - + * show all interfaces. */ + display_interfaces(slave_ifname /* == NULL */); + return 2; /* why 2? */ + } + /* A single arg means show the + * configuration for this interface + */ + display_interfaces(master_ifname); + return EXIT_SUCCESS; + } -static int set_if_down(char *ifname, int flags) -{ - int res = set_if_flags(ifname, flags & ~IFF_UP); - if (res) - bb_perror_msg("%s: can't down", ifname); - return res; -} + res = get_if_settings(master_ifname, &master); + if (res) { + /* Probably a good reason not to go on */ + bb_perror_msg_and_die("%s: can't get settings", master_ifname); + } -static int clear_if_addr(char *ifname) -{ - struct ifreq ifr; + /* check if master is indeed a master; + * if not then fail any operation + */ + if (!(master.flags.ifr_flags & IFF_MASTER)) + bb_error_msg_and_die("%s is not a master", master_ifname); - ifr.ifr_addr.sa_family = AF_INET; - memset(ifr.ifr_addr.sa_data, 0, sizeof(ifr.ifr_addr.sa_data)); - return set_ifrname_and_do_ioctl(SIOCSIFADDR, &ifr, ifname); -} + /* check if master is up; if not then fail any operation */ + if (!(master.flags.ifr_flags & IFF_UP)) + bb_error_msg_and_die("%s is not up", master_ifname); -static int set_if_addr(char *master_ifname, char *slave_ifname) -{ -#if (SIOCGIFADDR | SIOCSIFADDR \ - | SIOCGIFDSTADDR | SIOCSIFDSTADDR \ - | SIOCGIFBRDADDR | SIOCSIFBRDADDR \ - | SIOCGIFNETMASK | SIOCSIFNETMASK) <= 0xffff -#define INT uint16_t -#else -#define INT int -#endif - static const struct { - INT g_ioctl; - INT s_ioctl; - } ifra[] = { - { SIOCGIFADDR, SIOCSIFADDR }, - { SIOCGIFDSTADDR, SIOCSIFDSTADDR }, - { SIOCGIFBRDADDR, SIOCSIFBRDADDR }, - { SIOCGIFNETMASK, SIOCSIFNETMASK }, - }; + /* No opts: neither -c[hange] nor -d[etach] -> it's "enslave" then; + * and -f[orce] is not there too */ + if (!opt) { + /* The family '1' is ARPHRD_ETHER for ethernet. */ + if (master.hwaddr.ifr_hwaddr.sa_family != 1) { + bb_error_msg_and_die( + "%s is not ethernet-like (-f overrides)", + master_ifname); + } + } - struct ifreq ifr; - int res; - unsigned i; + /* Accepts only one slave */ + if (opt & OPT_c) { + /* change active slave */ + if (get_slave_flags(slave_ifname)) { + bb_perror_msg_and_die( + "%s: can't get flags", slave_ifname); + } + change_active(master_ifname, slave_ifname); + return EXIT_SUCCESS; + } - for (i = 0; i < ARRAY_SIZE(ifra); i++) { - res = set_ifrname_and_do_ioctl(ifra[i].g_ioctl, &ifr, master_ifname); - if (res < 0) { - ifr.ifr_addr.sa_family = AF_INET; - memset(ifr.ifr_addr.sa_data, 0, - sizeof(ifr.ifr_addr.sa_data)); + /* Accept multiple slaves */ + res = 0; + do { + if (opt & OPT_d) { + /* detach a slave interface from the master */ + rv = get_slave_flags(slave_ifname); + if (rv) { + /* Can't work with this slave, */ + /* remember the error and skip it */ + bb_perror_msg( + "skipping %s: can't get flags", + slave_ifname); + res = rv; + continue; + } + rv = release(master_ifname, slave_ifname); + if (rv) { + bb_perror_msg( + "master %s, slave %s: " + "can't release", + master_ifname, slave_ifname); + res = rv; + } + } else { + /* attach a slave interface to the master */ + rv = get_if_settings(slave_ifname, &slave); + if (rv) { + /* Can't work with this slave, */ + /* remember the error and skip it */ + bb_perror_msg( + "skipping %s: can't get settings", + slave_ifname); + res = rv; + continue; + } + rv = enslave(master_ifname, slave_ifname); + if (rv) { + bb_perror_msg( + "master %s, slave %s: " + "can't enslave", + master_ifname, slave_ifname); + res = rv; + } } + } while ((slave_ifname = *argv++) != NULL); - res = set_ifrname_and_do_ioctl(ifra[i].s_ioctl, &ifr, slave_ifname); - if (res < 0) - return res; + if (ENABLE_FEATURE_CLEAN_UP) { + close(skfd); } - return 0; + return res; } |