[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