summaryrefslogtreecommitdiffstats
path: root/src/net/ndp.c
diff options
context:
space:
mode:
authorMichael Brown2013-11-08 15:35:29 +0100
committerMichael Brown2013-11-14 13:35:43 +0100
commit2fa34085e28992dd7409496709af822776bd8fc6 (patch)
tree39a5bccb33c9b67eb2c93c950be39927f146a543 /src/net/ndp.c
parent[ipv6] Add "ipv6" setting type (diff)
downloadipxe-2fa34085e28992dd7409496709af822776bd8fc6.tar.gz
ipxe-2fa34085e28992dd7409496709af822776bd8fc6.tar.xz
ipxe-2fa34085e28992dd7409496709af822776bd8fc6.zip
[dhcpv6] Add basic support for stateful and stateless DHCPv6
Add support for the stateful and stateless variants of the DHCPv6 protocol. The resulting settings block is registered as "net<x>.dhcpv6", and DHCPv6 options can be obtained using e.g. "${net0.dhcpv6/23:ipv6}" to obtain the IPv6 DNS server address. IPv6 addresses obtained via stateful DHCPv6 are not yet applied to the network device. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net/ndp.c')
-rw-r--r--src/net/ndp.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/src/net/ndp.c b/src/net/ndp.c
index 1b1109ed..f56bbe92 100644
--- a/src/net/ndp.c
+++ b/src/net/ndp.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/ipv6.h>
#include <ipxe/icmpv6.h>
#include <ipxe/neighbour.h>
+#include <ipxe/dhcpv6.h>
#include <ipxe/ndp.h>
/** @file
@@ -596,6 +597,8 @@ struct ipv6conf {
/** Job control interface */
struct interface job;
+ /** DHCPv6 interface */
+ struct interface dhcp;
/** Network device being configured */
struct net_device *netdev;
@@ -646,6 +649,7 @@ static void ipv6conf_done ( struct ipv6conf *ipv6conf, int rc ) {
/* Shut down interfaces */
intf_shutdown ( &ipv6conf->job, rc );
+ intf_shutdown ( &ipv6conf->dhcp, rc );
/* Stop timer */
stop_timer ( &ipv6conf->timer );
@@ -686,6 +690,8 @@ static void ipv6conf_expired ( struct retry_timer *timer, int fail ) {
static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
unsigned int flags ) {
struct ipv6conf *ipv6conf;
+ int stateful;
+ int rc;
/* Identify IPv6 configurator, if any */
ipv6conf = ipv6conf_demux ( netdev );
@@ -697,13 +703,28 @@ static int ipv6conf_rx_router_advertisement ( struct net_device *netdev,
return 0;
}
- /* Fail if stateful address autoconfiguration is required */
- if ( flags & NDP_ROUTER_MANAGED ) {
- ipv6conf_done ( ipv6conf, -ENOTSUP );
- return -ENOTSUP;
+ /* If this is not the first solicited router advertisement, ignore it */
+ if ( ! timer_running ( &ipv6conf->timer ) )
+ return 0;
+
+ /* Stop router solicitation timer */
+ stop_timer ( &ipv6conf->timer );
+
+ /* Start DHCPv6 if required */
+ if ( flags & ( NDP_ROUTER_MANAGED | NDP_ROUTER_OTHER ) ) {
+ stateful = ( flags & NDP_ROUTER_MANAGED );
+ if ( ( rc = start_dhcpv6 ( &ipv6conf->dhcp, netdev,
+ stateful ) ) != 0 ) {
+ DBGC ( netdev, "NDP could not start state%s DHCPv6: "
+ "%s\n", ( stateful ? "ful" : "less" ),
+ strerror ( rc ) );
+ ipv6conf_done ( ipv6conf, rc );
+ return rc;
+ }
+ return 0;
}
- /* Mark autoconfiguration as complete */
+ /* Otherwise, terminate autoconfiguration */
ipv6conf_done ( ipv6conf, 0 );
return 0;
@@ -718,6 +739,15 @@ static struct interface_operation ipv6conf_job_op[] = {
static struct interface_descriptor ipv6conf_job_desc =
INTF_DESC ( struct ipv6conf, job, ipv6conf_job_op );
+/** IPv6 configurator DHCPv6 interface operations */
+static struct interface_operation ipv6conf_dhcp_op[] = {
+ INTF_OP ( intf_close, struct ipv6conf *, ipv6conf_done ),
+};
+
+/** IPv6 configurator DHCPv6 interface descriptor */
+static struct interface_descriptor ipv6conf_dhcp_desc =
+ INTF_DESC ( struct ipv6conf, dhcp, ipv6conf_dhcp_op );
+
/**
* Start IPv6 autoconfiguration
*
@@ -734,6 +764,7 @@ int start_ipv6conf ( struct interface *job, struct net_device *netdev ) {
return -ENOMEM;
ref_init ( &ipv6conf->refcnt, ipv6conf_free );
intf_init ( &ipv6conf->job, &ipv6conf_job_desc, &ipv6conf->refcnt );
+ intf_init ( &ipv6conf->dhcp, &ipv6conf_dhcp_desc, &ipv6conf->refcnt );
timer_init ( &ipv6conf->timer, ipv6conf_expired, &ipv6conf->refcnt );
ipv6conf->netdev = netdev_get ( netdev );