summaryrefslogtreecommitdiffstats
path: root/src/usr
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr')
-rw-r--r--src/usr/autoboot.c87
1 files changed, 80 insertions, 7 deletions
diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c
index 057b70cd0..45b3b6e7b 100644
--- a/src/usr/autoboot.c
+++ b/src/usr/autoboot.c
@@ -17,6 +17,7 @@
*/
#include <string.h>
+#include <errno.h>
#include <vsprintf.h>
#include <gpxe/netdevice.h>
#include <usr/ifmgmt.h>
@@ -30,21 +31,93 @@
void test_dhcp ( struct net_device *netdev );
-void autoboot ( void ) {
+/**
+ * Identify the boot network device
+ *
+ * @ret netdev Boot network device
+ */
+static struct net_device * find_boot_netdev ( void ) {
+ return NULL;
+}
+
+/**
+ * Get the next network device to try
+ *
+ * @ret netdev 'Next' network device
+ *
+ * This function will cycle through all registered network devices in
+ * order, returning NULL.
+ *
+ * This function should be safe against registration/deregistration of
+ * net devices between calls to next_netdev().
+ */
+static struct net_device * next_netdev ( void ) {
+ static struct net_device *last_netdev = NULL;
struct net_device *netdev;
- int rc;
for_each_netdev ( netdev ) {
+ if ( ! last_netdev ) {
+ last_netdev = netdev;
+ return netdev;
+ }
+ if ( last_netdev == netdev )
+ last_netdev = NULL;
+ }
- if ( ( rc = ifopen ( netdev ) ) != 0 )
- continue;
+ last_netdev = NULL;
+ return NULL;
+}
+
+/**
+ * Boot from a network device
+ *
+ * @v netdev Network device
+ */
+void netboot ( struct net_device *netdev ) {
+
+ /* Open device and display device status */
+ if ( ifopen ( netdev ) != 0 )
+ return;
+ ifstat ( netdev );
- ifstat ( netdev );
+ test_dhcp ( netdev );
+}
+
+/**
+ * Close all open net devices
+ *
+ * Called before a fresh boot attempt in order to free up memory. We
+ * don't just close the device immediately after the boot fails,
+ * because there may still be TCP connections in the process of
+ * closing.
+ */
+static void close_all_netdevs ( void ) {
+ struct net_device *netdev;
- test_dhcp ( netdev );
-
+ for_each_netdev ( netdev ) {
ifclose ( netdev );
}
+}
+
+/**
+ * Boot the system
+ */
+void autoboot ( void ) {
+ struct net_device *boot_netdev;
+ struct net_device *netdev;
+
+ /* If we have an identifable boot device, try that first */
+ close_all_netdevs();
+ if ( ( boot_netdev = find_boot_netdev() ) )
+ netboot ( boot_netdev );
+
+ /* If that fails, try booting from any of the other devices */
+ for_each_netdev ( netdev ) {
+ if ( netdev == boot_netdev )
+ continue;
+ close_all_netdevs();
+ netboot ( netdev );
+ }
printf ( "No more network devices\n" );
}