summaryrefslogtreecommitdiffstats
path: root/net/ifup.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ifup.c')
-rw-r--r--net/ifup.c244
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