[gPXE-devel] [PATCH 01/31] [ipv6] Added an "ipv6" command that performs stateless autoconfiguration on a given network interface. Does not yet assign the address to the netdevice.

matthew at theiselins.net matthew at theiselins.net
Fri Jul 8 10:28:10 EDT 2011


From: Matthew Iselin <matthew at theiselins.net>

Signed-off-by: Matthew Iselin <matthew at theiselins.net>
---
 src/config/config.c         |    3 +
 src/config/general.h        |    1 +
 src/hci/commands/ipv6_cmd.c |  180 +++++++++++++++++++++++++++++++++++++++++++
 src/include/usr/ip6mgmt.h   |   17 ++++
 src/usr/ip6mgmt.c           |   76 ++++++++++++++++++
 5 files changed, 277 insertions(+), 0 deletions(-)
 create mode 100644 src/hci/commands/ipv6_cmd.c
 create mode 100644 src/include/usr/ip6mgmt.h
 create mode 100644 src/usr/ip6mgmt.c

diff --git a/src/config/config.c b/src/config/config.c
index f468064..cf6d6ba 100644
--- a/src/config/config.c
+++ b/src/config/config.c
@@ -238,6 +238,9 @@ REQUIRE_OBJECT ( digest_cmd );
 #ifdef PXE_CMD
 REQUIRE_OBJECT ( pxe_cmd );
 #endif
+#ifdef IPV6_CMD
+REQUIRE_OBJECT ( ipv6_cmd );
+#endif
 
 /*
  * Drag in miscellaneous objects
diff --git a/src/config/general.h b/src/config/general.h
index b58dff9..0bb364e 100644
--- a/src/config/general.h
+++ b/src/config/general.h
@@ -121,6 +121,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #undef	TIME_CMD		/* Time commands */
 #undef	DIGEST_CMD		/* Image crypto digest commands */
 //#undef	PXE_CMD			/* PXE commands */
+#define IPV6_CMD		/* IPv6 commands */
 
 /*
  * Error message tables to include
diff --git a/src/hci/commands/ipv6_cmd.c b/src/hci/commands/ipv6_cmd.c
new file mode 100644
index 0000000..e794e6c
--- /dev/null
+++ b/src/hci/commands/ipv6_cmd.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2011 Matthew Iselin <matthew at theiselins.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * 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 details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/in.h>
+#include <gpxe/command.h>
+#include <usr/ip6mgmt.h>
+#include <usr/ifmgmt.h>
+
+/** @file
+ *
+ * IPv6 management commands
+ *
+ */
+
+/**
+ * "ipv6" command syntax message
+ *
+ * @v argv		Argument list
+ */
+static void ipv6_syntax ( char **argv ) {
+	printf ( "Usage:\n"
+		 "  %s <interface> [<interface> ...]\n"
+		 "  %s any\n"
+		 "\n"
+		 "Prepare a network interface for use with IPv6\n",
+		 argv[0], argv[0] );
+}
+
+
+/**
+ * Attempt to configure a device with an IPv6 link-local address
+ *
+ * @v netdev		Device to configure
+ * @ret rc		Exit code
+ */
+static int ipv6_one_device ( struct net_device *netdev ) {
+	int rc;
+
+	/* Perform autoconfiguration */
+	if ( ( rc = ip6_autoconf ( netdev ) ) != 0 ) {
+		/* Close the device on error to avoid out-of-memory */
+		netdev_close ( netdev );
+
+		printf ( "Could not configure %s: %s\n", netdev->name,
+			 strerror ( rc ) );
+		return 1;
+	}
+
+	return 0;
+}
+
+/**
+ * Call ipv6_one_device() for each name in argv
+ *
+ * @v argc		Number of devices
+ * @v argv		List of device names
+ * @ret rc		Exit code
+ */
+static int ipv6_each_device_name ( int argc, char **argv ) {
+	int i;
+	char *netdev_name;
+	struct net_device *netdev;
+
+	for ( i = 0; i < argc; i++ ) {
+		netdev_name = argv[i];
+		netdev = find_netdev ( netdev_name );
+
+		if ( ! netdev ) {
+			printf ( "No such interface: %s\n", netdev_name );
+			continue;
+		}
+
+		if ( ipv6_one_device ( netdev ) == 0 )
+			return 0;
+	}
+
+	printf ( "Could not configure any interface.\n" );
+	return 1;
+}
+
+/**
+ * Call ipv6_one_device() for each device in net_devices
+ *
+ * @ret rc		Exit code
+ */
+static int ipv6_each_device ( void ) {
+	struct net_device *netdev;
+
+	for_each_netdev ( netdev ) {
+		if ( ipv6_one_device ( netdev ) == 0 )
+			return 0;
+	}
+
+	printf ( "Could not configure any interface.\n" );
+	return 1;
+}
+
+/**
+ * The "ipv6" command
+ *
+ * @v argc		Argument count
+ * @v argv		Argument list
+ * @ret rc		Exit code
+ */
+static int ipv6_exec ( int argc __unused, char **argv __unused ) {
+	static struct option longopts[] = {
+		{ "help", 0, NULL, 'h' },
+		{ NULL, 0, NULL, 0 },
+	};
+	int c;
+
+	/* Parse options */
+	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+		switch ( c ) {
+		case 'h':
+			/* Display help text */
+		default:
+			/* Unrecognised/invalid option */
+			ipv6_syntax ( argv );
+			return 1;
+		}
+	}
+
+	/* Need one or more interface names remaining after the options */
+	if ( ( argc - optind ) < 1 ) {
+		ipv6_syntax ( argv );
+		return 1;
+	}
+
+	if ( strcmp ( argv[optind], "any" ) == 0 )
+		return ipv6_each_device();
+
+	return ipv6_each_device_name ( argc - optind, argv + optind );
+}
+
+static int dhcp6_exec ( int argc __unused, char **argv __unused ) {
+	printf ( "DHCPv6 is not yet implemented.\n" );
+	return 0;
+}
+
+/** IPv6 management commands */
+struct command ipv6_commands[] __command = {
+	{
+		.name = "ipv6",
+		.exec = ipv6_exec,
+	},
+	{
+		.name = "dhcp6",
+		.exec = dhcp6_exec,
+	}
+};
+
+
diff --git a/src/include/usr/ip6mgmt.h b/src/include/usr/ip6mgmt.h
new file mode 100644
index 0000000..9c17285
--- /dev/null
+++ b/src/include/usr/ip6mgmt.h
@@ -0,0 +1,17 @@
+#ifndef _USR_IPV6MGMT_H
+#define _USR_IPV6MGMT_H
+
+/** @file
+ *
+ * IPv6 management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+struct net_device;
+
+extern int ip6_autoconf ( struct net_device *netdev );
+
+#endif /* _USR_IPV6MGMT_H */
+
diff --git a/src/usr/ip6mgmt.c b/src/usr/ip6mgmt.c
new file mode 100644
index 0000000..0809c7b
--- /dev/null
+++ b/src/usr/ip6mgmt.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 Matthew Iselin <matthew at theiselins.net>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * 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 details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <gpxe/netdevice.h>
+#include <gpxe/in.h>
+#include <gpxe/ip6.h>
+#include <gpxe/monojob.h>
+#include <gpxe/process.h>
+#include <usr/ifmgmt.h>
+#include <usr/ip6mgmt.h>
+
+#define LINK_WAIT_MS	15000
+
+/* Maximum length of the link-layer address we'll insert as an EUI-64. */
+#define AUTOCONF_LL_MAX	6
+
+int ip6_autoconf ( struct net_device *netdev __unused ) {
+	struct in6_addr ip6addr;
+	size_t ll_size;
+	int rc;
+
+	/* Check we can open the interface first */
+	if ( ( rc = ifopen ( netdev ) ) != 0 )
+		return rc;
+
+	/* Wait for link-up */
+	if ( ( rc = iflinkwait ( netdev, LINK_WAIT_MS ) ) != 0 )
+		return rc;
+	
+	/* Create the host ID part of the IPv6 address from the Link-Layer
+	 * address on the netdevice. */
+	memset ( &ip6addr, 0, sizeof (struct in6_addr) );
+	
+	ll_size = netdev->ll_protocol->ll_addr_len;
+	if ( ll_size < 6 ) {
+		memcpy ( ip6addr.s6_addr + (8 - ll_size), netdev->ll_addr, ll_size );
+	} else {
+		/* Create an EUI-64 identifier. */
+		memcpy( ip6addr.s6_addr + 8, netdev->ll_addr, 3 );
+		memcpy( ip6addr.s6_addr + 8 + 5, netdev->ll_addr + 3, 3 );
+		ip6addr.s6_addr[11] = 0xFF;
+		ip6addr.s6_addr[12] = 0xFE;
+		
+		/* Designate that this is in fact an EUI-64. */
+		ip6addr.s6_addr[8] |= 0x2;
+	}
+	
+	/* Fill in the link-local prefix. */
+	ip6addr.s6_addr[0] = 0xFE;
+	ip6addr.s6_addr[1] = 0x80;
+	
+	DBG( "ip6 autoconfig address is %s\n", inet6_ntoa(ip6addr) );
+	
+	return 0;
+}
+
-- 
1.7.2.5



More information about the gPXE-devel mailing list