diff options
Diffstat (limited to 'net/ifup.c')
-rw-r--r-- | net/ifup.c | 244 |
1 files changed, 199 insertions, 45 deletions
diff --git a/net/ifup.c b/net/ifup.c index d550f82530..5b92ee794d 100644 --- a/net/ifup.c +++ b/net/ifup.c @@ -1,26 +1,14 @@ -/* - * ifup.c - bring up network interfaces - * - * Copyright (c) 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more detaiifup. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2014 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + +/* ifup.c - bring up network interfaces */ + #define pr_fmt(fmt) "ifup: " fmt #include <environment.h> #include <command.h> #include <common.h> +#include <complete.h> #include <getopt.h> #include <dhcp.h> #include <net.h> @@ -29,7 +17,6 @@ #include <string.h> #include <driver.h> #include <init.h> -#include <globalvar.h> #include <magicvar.h> #include <linux/stat.h> @@ -98,7 +85,7 @@ static int source_env_network(struct eth_device *edev) env_push_context(); for (i = 0; i < ARRAY_SIZE(vars); i++) - setenv(vars[i], ""); + unsetenv(vars[i]); cmd = basprintf("source /env/network/%s", edev->devname); ret = run_command(cmd); @@ -171,8 +158,8 @@ out: static void set_linux_bootarg(struct eth_device *edev) { + char *bootarg; if (edev->global_mode == ETH_MODE_STATIC) { - char *bootarg; IPaddr_t serverip; IPaddr_t gateway; @@ -188,10 +175,36 @@ static void set_linux_bootarg(struct eth_device *edev) dev_set_param(&edev->dev, "linux.bootargs", bootarg); free(bootarg); } else if (edev->global_mode == ETH_MODE_DHCP) { - dev_set_param(&edev->dev, "linux.bootargs", "ip=dhcp"); + bootarg = basprintf("ip=::::%s:%s:dhcp", + barebox_get_hostname(), + edev->linuxdevname ? edev->linuxdevname : ""); + dev_set_param(&edev->dev, "linux.bootargs", bootarg); + free(bootarg); } } +static int ifup_edev_conf(struct eth_device *edev, unsigned flags) +{ + int ret; + + if (edev->global_mode == ETH_MODE_DHCP) { + if (IS_ENABLED(CONFIG_NET_DHCP)) { + ret = dhcp(edev, NULL); + } else { + dev_err(&edev->dev, "DHCP support not available\n"); + ret = -ENOSYS; + } + if (ret) + return ret; + } + + set_linux_bootarg(edev); + + edev->ifup = true; + + return 0; +} + int ifup_edev(struct eth_device *edev, unsigned flags) { int ret; @@ -214,22 +227,20 @@ int ifup_edev(struct eth_device *edev, unsigned flags) if (ret) return ret; - if (edev->global_mode == ETH_MODE_DHCP) { - if (IS_ENABLED(CONFIG_NET_DHCP)) { - ret = dhcp(edev, NULL); - } else { - dev_err(&edev->dev, "DHCP support not available\n"); - ret = -ENOSYS; - } - if (ret) - return ret; - } + ret = eth_open(edev); + if (ret) + return ret; - set_linux_bootarg(edev); + if (flags & IFUP_FLAG_SKIP_CONF) + return 1; - edev->ifup = true; + return ifup_edev_conf(edev, flags); +} - return 0; +void ifdown_edev(struct eth_device *edev) +{ + eth_close(edev); + edev->ifup = false; } int ifup(const char *ethname, unsigned flags) @@ -248,11 +259,86 @@ int ifup(const char *ethname, unsigned flags) return ifup_edev(edev, flags); } +int ifdown(const char *ethname) +{ + struct eth_device *edev; + + edev = eth_get_byname(ethname); + if (!edev) + return -ENODEV; + + ifdown_edev(edev); + + return 0; +} + static int net_ifup_force_detect; -int ifup_all(unsigned flags) +static bool ifup_edev_need_conf(struct eth_device *edev) +{ + return edev->active && !edev->ifup && + edev->global_mode != ETH_MODE_DISABLED; +} + +static int __ifup_all_parallel(unsigned flags) { struct eth_device *edev; + unsigned netdev_count = 0; + u64 start; + int ret; + + for_each_netdev(edev) { + ret = ifup_edev(edev, flags | IFUP_FLAG_SKIP_CONF); + if (ret == 1) + netdev_count++; + } + + start = get_time_ns(); + while (netdev_count && !is_timeout(start, PHY_AN_TIMEOUT * SECOND)) { + for_each_netdev(edev) { + if ((flags & IFUP_FLAG_UNTIL_NET_SERVER) && net_get_server()) + return 0; + + if (ctrlc()) + return -EINTR; + + if (!ifup_edev_need_conf(edev)) + continue; + + ret = eth_carrier_poll_once(edev); + if (ret) + continue; + + ifup_edev_conf(edev, flags); + if (!edev->ifup) + continue; + + netdev_count--; + } + } + + return 0; +} + +static int __ifup_all_sequence(unsigned flags) +{ + struct eth_device *edev; + + for_each_netdev(edev) { + if ((flags & IFUP_FLAG_UNTIL_NET_SERVER) && net_get_server()) + return 0; + + if (ctrlc()) + return -EINTR; + + ifup_edev(edev, flags); + } + + return 0; +} + +int ifup_all(unsigned flags) +{ DIR *dir; struct dirent *d; @@ -275,10 +361,28 @@ int ifup_all(unsigned flags) list_empty(&netdev_list)) device_detect_all(); - for_each_netdev(edev) - ifup_edev(edev, flags); + /* + * In the future, we may add an iproute -r option that tries to + * resolve $global.net.server using each interface. For now, + * we only support the special case of $global.net.server being + * empty, i.e. the first DHCP lease setting $global.net.server + * will be what we're going with. + */ + if (net_get_server() && !net_get_gateway()) + flags &= ~IFUP_FLAG_UNTIL_NET_SERVER; + + if (flags & IFUP_FLAG_PARALLEL) + return __ifup_all_parallel(flags); + else + return __ifup_all_sequence(flags); +} - return 0; +void ifdown_all(void) +{ + struct eth_device *edev; + + for_each_netdev(edev) + ifdown_edev(edev); } static int ifup_all_init(void) @@ -289,23 +393,28 @@ static int ifup_all_init(void) } late_initcall(ifup_all_init); -BAREBOX_MAGICVAR_NAMED(global_net_ifup_force_detect, - global.net.ifup_force_detect, - "net: force detection of devices on ifup -a"); +BAREBOX_MAGICVAR(global.net.ifup_force_detect, + "net: force detection of devices on ifup -a"); #if IS_ENABLED(CONFIG_NET_CMD_IFUP) static int do_ifup(int argc, char *argv[]) { int opt; - unsigned flags = 0; + unsigned flags = IFUP_FLAG_PARALLEL; int all = 0; - while ((opt = getopt(argc, argv, "af")) > 0) { + while ((opt = getopt(argc, argv, "asf1")) > 0) { switch (opt) { case 'f': flags |= IFUP_FLAG_FORCE; break; + case '1': + flags |= IFUP_FLAG_UNTIL_NET_SERVER; + break; + case 's': + flags &= ~IFUP_FLAG_PARALLEL; + break; case 'a': all = 1; break; @@ -329,15 +438,60 @@ BAREBOX_CMD_HELP_TEXT("/env/network/<intf> file. See Documentation/user/networki BAREBOX_CMD_HELP_TEXT("") BAREBOX_CMD_HELP_TEXT("Options:") BAREBOX_CMD_HELP_OPT ("-a", "bring up all interfaces") +BAREBOX_CMD_HELP_OPT ("-s", "bring up interfaces in sequence, not in parallel") BAREBOX_CMD_HELP_OPT ("-f", "Force. Configure even if ip already set") +BAREBOX_CMD_HELP_OPT ("-1", "Early exit if DHCP sets $global.net.server") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(ifup) .cmd = do_ifup, BAREBOX_CMD_DESC("bring a network interface up") - BAREBOX_CMD_OPTS("[-af] [INTF]") + BAREBOX_CMD_OPTS("[-asf1] [INTF]") BAREBOX_CMD_GROUP(CMD_GRP_NET) + BAREBOX_CMD_COMPLETE(eth_complete) BAREBOX_CMD_HELP(cmd_ifup_help) BAREBOX_CMD_END +static int do_ifdown(int argc, char *argv[]) +{ + int opt; + int all = 0; + + while ((opt = getopt(argc, argv, "a")) > 0) { + switch (opt) { + case 'a': + all = 1; + break; + } + } + + if (all) { + ifdown_all(); + return 0; + } + + if (argc == optind) + return COMMAND_ERROR_USAGE; + + return ifdown(argv[optind]); +} + + + +BAREBOX_CMD_HELP_START(ifdown) +BAREBOX_CMD_HELP_TEXT("Disable a network interface") +BAREBOX_CMD_HELP_TEXT("") +BAREBOX_CMD_HELP_TEXT("Options:") +BAREBOX_CMD_HELP_OPT ("-a", "disable all interfaces") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(ifdown) + .cmd = do_ifdown, + BAREBOX_CMD_DESC("disable a network interface") + BAREBOX_CMD_OPTS("[-a] [INTF]") + BAREBOX_CMD_GROUP(CMD_GRP_NET) + BAREBOX_CMD_COMPLETE(eth_complete) + BAREBOX_CMD_HELP(cmd_ifdown_help) +BAREBOX_CMD_END + #endif |