From 0669ed85b83db2b21a94258dc6734c34f6e81cdd Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Tue, 28 Apr 2015 12:55:44 +0200 Subject: [PATCH 1/6] [ethernet] do not construct EUI-64 identifier for empty MAC If the MAC address is empty we should not construct an EUI-64 identifier, but rather return an error. Signed-off-by: Hannes Reinecke --- src/net/ethernet.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/net/ethernet.c b/src/net/ethernet.c index 26fdedea8e..1625a17ce9 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -46,6 +46,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Ethernet broadcast MAC address */ uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +/** Empty Ethernet MAC address */ +uint8_t eth_empty[ETH_ALEN]; + /** * Check if Ethernet packet has an 802.3 LLC header * @@ -232,7 +235,8 @@ int eth_eth_addr ( const void *ll_addr, void *eth_addr ) { * @ret rc Return status code */ int eth_eui64 ( const void *ll_addr, void *eui64 ) { - + if (!memcmp(ll_addr, eth_empty, ETH_ALEN)) + return -ENXIO; memcpy ( ( eui64 + 0 ), ( ll_addr + 0 ), 3 ); memcpy ( ( eui64 + 5 ), ( ll_addr + 3 ), 3 ); *( ( uint16_t * ) ( eui64 + 3 ) ) = htons ( 0xfffe ); From 045de223af61f56110be63b9d87eee6c9f193179 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 14 Jul 2014 08:26:13 +0200 Subject: [PATCH 2/6] [iscsi] Parse IPv6 address for rootpath The 'rootpath' variable might contain an IPv6 address in brackets [XX:XX::XX]. So update the parser to handle this address correctly. Signed-off-by: Hannes Reinecke --- src/net/tcp/iscsi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index ec004e4bad..efb58cfe20 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -1912,15 +1912,25 @@ static int iscsi_parse_root_path ( struct iscsi_session *iscsi, /* Split root path into component parts */ strcpy ( rp_copy, root_path ); while ( 1 ) { + int skip = 0; + + if (*rp == '[') { + rp++; + skip = 1; + } rp_comp[i++] = rp; if ( i == NUM_RP_COMPONENTS ) break; - for ( ; *rp != ':' ; rp++ ) { + for ( ; *rp != ':' || skip; rp++ ) { if ( ! *rp ) { DBGC ( iscsi, "iSCSI %p root path \"%s\" " "too short\n", iscsi, root_path ); return -EINVAL_ROOT_PATH_TOO_SHORT; } + if (*rp == ']') { + skip = 0; + *rp = '\0'; + } } *(rp++) = '\0'; } From b85555b352c04fe02c1a8b73aaefa2ad69e3a83a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 16 Jul 2014 08:56:33 +0200 Subject: [PATCH 3/6] [ibft] IPv6 support The iBFT table is defined to be used with both, IPv4 and IPv6. So update the iBFT handling to work with IPv6 addresses, too. This patch updates the iBFT handling to extract the net_device from the routing tables, which also removes the long-standing hack with 'last_used_netdev'. Signed-off-by: Hannes Reinecke --- src/drivers/block/ibft.c | 212 ++++++++++++++++++++++++++++-------- src/include/ipxe/ibft.h | 13 ++- src/include/ipxe/ip.h | 2 + src/include/ipxe/settings.h | 2 + src/net/ipv4.c | 4 +- 5 files changed, 183 insertions(+), 50 deletions(-) diff --git a/src/drivers/block/ibft.c b/src/drivers/block/ibft.c index 91a808d85d..7b9f8a292e 100644 --- a/src/drivers/block/ibft.c +++ b/src/drivers/block/ibft.c @@ -37,6 +37,8 @@ FILE_LICENCE ( BSD2 ); #include #include #include +#include +#include #include #include #include @@ -85,6 +87,13 @@ struct ibft_strings { size_t len; }; +static int ibft_ipaddr_is_ipv6 ( struct ibft_ipaddr *ipaddr ) +{ + uint8_t prefix[12] = { 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0xff, 0xff }; + return (memcmp(ipaddr->raw, &prefix, sizeof (prefix) )); +} + /** * Fill in an IP address field within iBFT * @@ -94,8 +103,8 @@ struct ibft_strings { static void ibft_set_ipaddr ( struct ibft_ipaddr *ipaddr, struct in_addr in ) { memset ( ipaddr, 0, sizeof ( *ipaddr ) ); if ( in.s_addr ) { - ipaddr->in = in; - ipaddr->ones = 0xffff; + ipaddr->in.in = in; + ipaddr->in.ones = 0xffff; } } @@ -120,6 +129,41 @@ static void ibft_set_ipaddr_setting ( struct settings *settings, } } +/** + * Fill in an IPv6 address field within iBFT + * + * @v ipaddr IP address field + * @v in6 IPv6 address + */ +static void ibft_set_ip6addr ( struct ibft_ipaddr *ipaddr, + struct in6_addr in6 ) { + memset ( ipaddr, 0, sizeof ( *ipaddr ) ); + if ( in6.s6_addr ) { + ipaddr->in6 = in6; + } +} + +/** + * Fill in an IPv6 address within iBFT from configuration setting + * + * @v settings Parent settings block, or NULL + * @v ipaddr address field + * @v setting Configuration setting + * @v count Maximum number of IP addresses + */ +static void ibft_set_ip6addr_setting ( struct settings *settings, + struct ibft_ipaddr *ipaddr, + const struct setting *setting, + unsigned int count ) { + struct in6_addr in6[count]; + unsigned int i; + + fetch_ipv6_array_setting ( settings, setting, in6, count ); + for ( i = 0 ; i < count ; i++ ) { + ibft_set_ip6addr ( &ipaddr[i], in6[i] ); + } +} + /** * Read IP address from iBFT (for debugging) * @@ -128,7 +172,10 @@ static void ibft_set_ipaddr_setting ( struct settings *settings, * @ret ipaddr IP address string */ static const char * ibft_ipaddr ( struct ibft_ipaddr *ipaddr ) { - return inet_ntoa ( ipaddr->in ); + if ( ibft_ipaddr_is_ipv6(ipaddr) ) + return inet6_ntoa( &ipaddr->in6 ); + else + return inet_ntoa ( ipaddr->in.in ); } /** @@ -222,40 +269,35 @@ static const char * ibft_string ( struct ibft_strings *strings, } /** - * Fill in NIC portion of iBFT + * Fill in IPv4 specific parts of the NIC portion of iBFT * * @v nic NIC portion of iBFT - * @v strings iBFT string block descriptor - * @v netdev Network device - * @ret rc Return status code + * @v dest IPv4 target address + * @ret netdev Return Network device */ -static int ibft_fill_nic ( struct ibft_nic *nic, - struct ibft_strings *strings, - struct net_device *netdev ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; +static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, + struct sockaddr_in *dest) { + struct ipv4_miniroute *route4 = ipv4_route(dest->sin_scope_id, + &dest->sin_addr); + struct settings *parent; + struct settings *origin; struct in_addr netmask_addr = { 0 }; unsigned int netmask_count = 0; - struct settings *parent = netdev_settings ( netdev ); - struct settings *origin; - int rc; - - /* Fill in common header */ - nic->header.structure_id = IBFT_STRUCTURE_ID_NIC; - nic->header.version = 1; - nic->header.length = cpu_to_le16 ( sizeof ( *nic ) ); - nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID | - IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ); /* Determine origin of IP address */ + parent = netdev_settings(route4->netdev); fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); + nic->origin = ( ( origin == parent ) ? IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); DBG ( "iBFT NIC origin = %d\n", nic->origin ); /* Extract values from configuration settings */ - ibft_set_ipaddr_setting ( parent, &nic->ip_address, &ip_setting, 1 ); + fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); + + ibft_set_ipaddr ( &nic->ip_address, route4->address ); DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) ); - ibft_set_ipaddr_setting ( parent, &nic->gateway, &gateway_setting, 1 ); + ibft_set_ipaddr ( &nic->gateway, route4->gateway ); DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) ); ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting, ( sizeof ( nic->dns ) / @@ -263,14 +305,8 @@ static int ibft_fill_nic ( struct ibft_nic *nic, ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 ); DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) ); DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) ); - if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname, - &hostname_setting ) ) != 0 ) - return rc; - DBG ( "iBFT NIC hostname = %s\n", - ibft_string ( strings, &nic->hostname ) ); - /* Derive subnet mask prefix from subnet mask */ - fetch_ipv4_setting ( parent, &netmask_setting, &netmask_addr ); + netmask_addr = route4->netmask; while ( netmask_addr.s_addr ) { if ( netmask_addr.s_addr & 0x1 ) netmask_count++; @@ -278,10 +314,81 @@ static int ibft_fill_nic ( struct ibft_nic *nic, } nic->subnet_mask_prefix = netmask_count; DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix ); + return route4->netdev; +} + +/** + * Fill in IPv6 specific parts of the NIC portion of iBFT + * + * @v nic NIC portion of iBFT + * @v dest IPv6 destination address + * @ret rc Return network device + */ +static struct net_device * ibft_fill_nic_ipv6 ( struct ibft_nic *nic, + struct sockaddr_in6 * dest ) { + struct ipv6_miniroute *route6; + struct in6_addr *router = &dest->sin6_addr; + struct settings *parent; + struct settings *origin; + + route6 = ipv6_route(dest->sin6_scope_id, &router); + parent = netdev_settings(route6->netdev); + fetch_setting ( parent, &ip6_setting, &origin, NULL, NULL, 0 ); + nic->origin = ( ( origin == parent ) ? + IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); + DBG ( "iBFT NIC origin = %d\n", nic->origin ); + + /* Extract values from configuration settings */ + ibft_set_ip6addr ( &nic->ip_address, route6->address ); + DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) ); + ibft_set_ip6addr ( &nic->gateway, *router ); + DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) ); + ibft_set_ip6addr_setting ( NULL, &nic->dns[0], &dns6_setting, + ( sizeof ( nic->dns ) / + sizeof ( nic->dns[0] ) ) ); + DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) ); + DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) ); + nic->subnet_mask_prefix = route6->prefix_len; + DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix ); + + return route6->netdev; +} + +/** + * Fill in NIC portion of iBFT + * + * @v nic NIC portion of iBFT + * @v strings iBFT string block descriptor + * @v netdev Network device + * @ret rc Return status code + */ +static int ibft_fill_nic ( struct ibft_nic *nic, + struct ibft_strings *strings, + struct iscsi_session *iscsi ) { + struct sockaddr_in *sin_target = + ( struct sockaddr_in * ) &iscsi->target_sockaddr; + struct sockaddr_in6 *sin6_target = + ( struct sockaddr_in6 * ) &iscsi->target_sockaddr; + struct net_device *netdev; + struct ll_protocol *ll_protocol; + int rc; + + /* Fill in common header */ + nic->header.structure_id = IBFT_STRUCTURE_ID_NIC; + nic->header.version = 1; + nic->header.length = cpu_to_le16 ( sizeof ( *nic ) ); + nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID | + IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ); + + if (sin_target->sin_family == AF_INET) + netdev = ibft_fill_nic_ipv4( nic, sin_target ); + else + netdev = ibft_fill_nic_ipv6( nic, sin6_target ); /* Extract values from net-device configuration */ nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) ); DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) ); + ll_protocol = netdev->ll_protocol; if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, nic->mac_address ) ) != 0 ) { DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) ); @@ -291,6 +398,12 @@ static int ibft_fill_nic ( struct ibft_nic *nic, nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location ); DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) ); + if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname, + &hostname_setting ) ) != 0 ) + return rc; + DBG ( "iBFT NIC hostname = %s\n", + ibft_string ( strings, &nic->hostname ) ); + return 0; } @@ -405,8 +518,16 @@ static int ibft_fill_target ( struct ibft_target *target, struct iscsi_session *iscsi ) { struct sockaddr_in *sin_target = ( struct sockaddr_in * ) &iscsi->target_sockaddr; + struct sockaddr_in6 *sin6_target = + ( struct sockaddr_in6 * ) &iscsi->target_sockaddr; int rc; + if (sin6_target->sin6_family != AF_INET6 && + sin_target->sin_family != AF_INET) { + DBG ( "iBFT invalid IP address type %d\n", + sin6_target->sin6_family ); + return -EPROTONOSUPPORT; + } /* Fill in common header */ target->header.structure_id = IBFT_STRUCTURE_ID_TARGET; target->header.version = 1; @@ -415,10 +536,19 @@ static int ibft_fill_target ( struct ibft_target *target, IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ); /* Fill in Target values */ - ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr ); - DBG ( "iBFT target IP = %s\n", ibft_ipaddr ( &target->ip_address ) ); - target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) ); - DBG ( "iBFT target port = %d\n", target->socket ); + if (sin_target->sin_family == AF_INET) { + ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr ); + DBG ( "iBFT target IP = %s\n", + ibft_ipaddr ( &target->ip_address ) ); + target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) ); + DBG ( "iBFT target port = %d\n", target->socket ); + } else { + ibft_set_ip6addr ( &target->ip_address, sin6_target->sin6_addr ); + DBG ( "iBFT target IP = %s\n", + ibft_ipaddr ( &target->ip_address ) ); + target->socket = cpu_to_le16 ( ntohs ( sin6_target->sin6_port ) ); + DBG ( "iBFT target port = %d\n", target->socket ); + } memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) ); DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n", SCSI_LUN_DATA ( target->boot_lun ) ); @@ -454,19 +584,8 @@ int ibft_describe ( struct iscsi_session *iscsi, .offset = offsetof ( typeof ( *ibft ), strings ), .len = len, }; - struct net_device *netdev; int rc; - /* Ugly hack. Now that we have a generic interface mechanism - * that can support ioctls, we can potentially eliminate this. - */ - netdev = last_opened_netdev(); - if ( ! netdev ) { - DBGC ( iscsi, "iSCSI %p cannot guess network device\n", - iscsi ); - return -ENODEV; - } - /* Fill in ACPI header */ ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG ); ibft->table.acpi.length = cpu_to_le32 ( len ); @@ -485,7 +604,8 @@ int ibft_describe ( struct iscsi_session *iscsi, cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) ); /* Fill in NIC, Initiator and Target blocks */ - if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, netdev ) ) != 0 ) + if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, + iscsi ) ) != 0 ) return rc; if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings, iscsi ) ) != 0 ) diff --git a/src/include/ipxe/ibft.h b/src/include/ipxe/ibft.h index 35f15105c9..756197a47c 100644 --- a/src/include/ipxe/ibft.h +++ b/src/include/ipxe/ibft.h @@ -63,14 +63,23 @@ struct ibft_string { ibft_off_t offset; } __attribute__ (( packed )); -/** An IP address within the iBFT */ -struct ibft_ipaddr { +/** iBFT IPv4 address representation */ +struct ibft_inaddr { /** Reserved; must be zero */ uint16_t zeroes[5]; /** Must be 0xffff if IPv4 address is present, otherwise zero */ uint16_t ones; /** The IPv4 address, or zero if not present */ struct in_addr in; +}; + +/** An IP address within the iBFT */ +struct ibft_ipaddr { + union { + struct ibft_inaddr in; + struct in6_addr in6; + uint8_t raw[16]; + }; } __attribute__ (( packed )); /** diff --git a/src/include/ipxe/ip.h b/src/include/ipxe/ip.h index 285be6dcd7..144d2539e4 100644 --- a/src/include/ipxe/ip.h +++ b/src/include/ipxe/ip.h @@ -75,6 +75,8 @@ extern struct list_head ipv4_miniroutes; extern struct net_protocol ipv4_protocol __net_protocol; extern int ipv4_has_any_addr ( struct net_device *netdev ); +extern struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, + struct in_addr *dest ); extern int parse_ipv4_setting ( const struct setting_type *type, const char *value, void *buf, size_t len ); extern int format_ipv4_setting ( const struct setting_type *type, diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 341fc3c7f7..3cb4689197 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -444,6 +444,8 @@ len6_setting __setting ( SETTING_IP6, len6 ); extern const struct setting gateway6_setting __setting ( SETTING_IP6, gateway6 ); extern const struct setting +dns6_setting __setting ( SETTING_IP_EXTRA, dns6 ); +extern const struct setting hostname_setting __setting ( SETTING_HOST, hostname ); extern const struct setting domain_setting __setting ( SETTING_IP_EXTRA, domain ); diff --git a/src/net/ipv4.c b/src/net/ipv4.c index b4148d8e03..ba07098c06 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -147,8 +147,8 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { * If the route requires use of a gateway, the next hop destination * address will be overwritten with the gateway address. */ -static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, - struct in_addr *dest ) { +struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, + struct in_addr *dest ) { struct ipv4_miniroute *miniroute; /* Find first usable route in routing table */ From e929273d4fc38207c92ef457ef2fe867cae2638f Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 16 Jul 2014 10:42:24 +0200 Subject: [PATCH 4/6] [ibft] multiple session support It is possible to open several iSCSI sessions, so we should be updating the iBFT tables to handle several connections. As the iBFT table is initialized on every call we need to keep a global list of iSCSI sessions to fill out the iBFT table correctly. Signed-off-by: Hannes Reinecke --- src/drivers/block/ibft.c | 201 +++++++++++++++++++++++++++++---------- src/include/ipxe/iscsi.h | 6 ++ src/net/tcp/iscsi.c | 5 + 3 files changed, 160 insertions(+), 52 deletions(-) diff --git a/src/drivers/block/ibft.c b/src/drivers/block/ibft.c index 7b9f8a292e..75885285c8 100644 --- a/src/drivers/block/ibft.c +++ b/src/drivers/block/ibft.c @@ -64,10 +64,14 @@ struct ipxe_ibft { struct ibft_table table; /** The Initiator section */ struct ibft_initiator initiator __attribute__ (( aligned ( 16 ) )); - /** The NIC section */ - struct ibft_nic nic __attribute__ (( aligned ( 16 ) )); - /** The Target section */ - struct ibft_target target __attribute__ (( aligned ( 16 ) )); + /** The 1. NIC section */ + struct ibft_nic nic0 __attribute__ (( aligned ( 16 ) )); + /** The 1. Target section */ + struct ibft_target target0 __attribute__ (( aligned ( 16 ) )); + /** The 2. NIC section */ + struct ibft_nic nic1 __attribute__ (( aligned ( 16 ) )); + /** The 2. Target section */ + struct ibft_target target1 __attribute__ (( aligned ( 16 ) )); /** Strings block */ char strings[0]; } __attribute__ (( packed, aligned ( 16 ) )); @@ -276,9 +280,7 @@ static const char * ibft_string ( struct ibft_strings *strings, * @ret netdev Return Network device */ static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, - struct sockaddr_in *dest) { - struct ipv4_miniroute *route4 = ipv4_route(dest->sin_scope_id, - &dest->sin_addr); + struct ipv4_miniroute *route4 ) { struct settings *parent; struct settings *origin; struct in_addr netmask_addr = { 0 }; @@ -290,20 +292,24 @@ static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, nic->origin = ( ( origin == parent ) ? IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); - DBG ( "iBFT NIC origin = %d\n", nic->origin ); + DBG ( "iBFT NIC[%d] origin = %d\n", + nic->header.index, nic->origin ); /* Extract values from configuration settings */ fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); ibft_set_ipaddr ( &nic->ip_address, route4->address ); - DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) ); + DBG ( "iBFT NIC[%d] IP = %s\n", nic->header.index, + ibft_ipaddr ( &nic->ip_address ) ); ibft_set_ipaddr ( &nic->gateway, route4->gateway ); - DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) ); + DBG ( "iBFT NIC[%d] gateway = %s\n", nic->header.index, + ibft_ipaddr ( &nic->gateway ) ); ibft_set_ipaddr_setting ( NULL, &nic->dns[0], &dns_setting, ( sizeof ( nic->dns ) / sizeof ( nic->dns[0] ) ) ); ibft_set_ipaddr_setting ( parent, &nic->dhcp, &dhcp_server_setting, 1 ); - DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) ); + DBG ( "iBFT NIC[%d] DNS = %s", nic->header.index, + ibft_ipaddr ( &nic->dns[0] ) ); DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) ); /* Derive subnet mask prefix from subnet mask */ netmask_addr = route4->netmask; @@ -313,7 +319,8 @@ static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, netmask_addr.s_addr >>= 1; } nic->subnet_mask_prefix = netmask_count; - DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix ); + DBG ( "iBFT NIC[%d] subnet = /%d\n", nic->header.index, + nic->subnet_mask_prefix ); return route4->netdev; } @@ -325,31 +332,34 @@ static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, * @ret rc Return network device */ static struct net_device * ibft_fill_nic_ipv6 ( struct ibft_nic *nic, - struct sockaddr_in6 * dest ) { - struct ipv6_miniroute *route6; - struct in6_addr *router = &dest->sin6_addr; + struct ipv6_miniroute *route6, + struct in6_addr * router ) { struct settings *parent; struct settings *origin; - route6 = ipv6_route(dest->sin6_scope_id, &router); parent = netdev_settings(route6->netdev); fetch_setting ( parent, &ip6_setting, &origin, NULL, NULL, 0 ); nic->origin = ( ( origin == parent ) ? IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); - DBG ( "iBFT NIC origin = %d\n", nic->origin ); + DBG ( "iBFT NIC[%d] origin = %d\n", + nic->header.index, nic->origin ); /* Extract values from configuration settings */ ibft_set_ip6addr ( &nic->ip_address, route6->address ); - DBG ( "iBFT NIC IP = %s\n", ibft_ipaddr ( &nic->ip_address ) ); + DBG ( "iBFT NIC[%d] IP = %s\n", + nic->header.index, ibft_ipaddr ( &nic->ip_address ) ); ibft_set_ip6addr ( &nic->gateway, *router ); - DBG ( "iBFT NIC gateway = %s\n", ibft_ipaddr ( &nic->gateway ) ); + DBG ( "iBFT NIC[%d] gateway = %s\n", + nic->header.index, ibft_ipaddr ( &nic->gateway ) ); ibft_set_ip6addr_setting ( NULL, &nic->dns[0], &dns6_setting, ( sizeof ( nic->dns ) / sizeof ( nic->dns[0] ) ) ); - DBG ( "iBFT NIC DNS = %s", ibft_ipaddr ( &nic->dns[0] ) ); + DBG ( "iBFT NIC[%d] DNS = %s", nic->header.index, + ibft_ipaddr ( &nic->dns[0] ) ); DBG ( ", %s\n", ibft_ipaddr ( &nic->dns[1] ) ); nic->subnet_mask_prefix = route6->prefix_len; - DBG ( "iBFT NIC subnet = /%d\n", nic->subnet_mask_prefix ); + DBG ( "iBFT NIC[%d] subnet = /%d\n", + nic->header.index, nic->subnet_mask_prefix ); return route6->netdev; } @@ -364,44 +374,85 @@ static struct net_device * ibft_fill_nic_ipv6 ( struct ibft_nic *nic, */ static int ibft_fill_nic ( struct ibft_nic *nic, struct ibft_strings *strings, - struct iscsi_session *iscsi ) { + struct iscsi_session *iscsi, + int nic_index ) { struct sockaddr_in *sin_target = ( struct sockaddr_in * ) &iscsi->target_sockaddr; struct sockaddr_in6 *sin6_target = ( struct sockaddr_in6 * ) &iscsi->target_sockaddr; + struct ipv4_miniroute * route4 = NULL; + struct ipv6_miniroute * route6 = NULL; + struct in6_addr *router6; struct net_device *netdev; struct ll_protocol *ll_protocol; int rc; + if (sin_target->sin_family == AF_INET) { + struct in_addr router4 = sin_target->sin_addr; + route4 = ipv4_route(sin_target->sin_scope_id, &router4); + if (!route4) { + DBG ( "iBFT NIC[%d] IPv6 host unreachable\n", + nic_index ); + return -EHOSTUNREACH; + } + if (nic->header.flags & IBFT_FL_NIC_BLOCK_VALID) { + struct ibft_ipaddr tmp; + ibft_set_ipaddr( &tmp, route4->address ); + if (memcmp(&nic->ip_address, &tmp, sizeof(tmp))) + return -EBUSY; + } + } else if (sin6_target->sin6_family == AF_INET6) { + router6 = &sin6_target->sin6_addr; + route6 = ipv6_route(sin6_target->sin6_scope_id, &router6); + if (!route6) { + DBG ( "iBFT NIC[%d] IPv6 host unreachable\n", + nic_index ); + return -EHOSTUNREACH; + } + if (nic->header.flags & IBFT_FL_NIC_BLOCK_VALID) { + struct ibft_ipaddr tmp; + ibft_set_ip6addr( &tmp, route6->address ); + if (memcmp(&nic->ip_address, &tmp, sizeof(tmp))) + return -EBUSY; + } + } else + return -EPROTONOSUPPORT; + + /* Fill in common header */ nic->header.structure_id = IBFT_STRUCTURE_ID_NIC; nic->header.version = 1; + nic->header.index = nic_index; nic->header.length = cpu_to_le16 ( sizeof ( *nic ) ); nic->header.flags = ( IBFT_FL_NIC_BLOCK_VALID | IBFT_FL_NIC_FIRMWARE_BOOT_SELECTED ); if (sin_target->sin_family == AF_INET) - netdev = ibft_fill_nic_ipv4( nic, sin_target ); + netdev = ibft_fill_nic_ipv4( nic, route4 ); else - netdev = ibft_fill_nic_ipv6( nic, sin6_target ); + netdev = ibft_fill_nic_ipv6( nic, route6, router6 ); /* Extract values from net-device configuration */ nic->vlan = cpu_to_le16 ( vlan_tag ( netdev ) ); - DBG ( "iBFT NIC VLAN = %02x\n", le16_to_cpu ( nic->vlan ) ); + DBG ( "iBFT NIC[%d] VLAN = %02x\n", + nic->header.index, le16_to_cpu ( nic->vlan ) ); ll_protocol = netdev->ll_protocol; if ( ( rc = ll_protocol->eth_addr ( netdev->ll_addr, nic->mac_address ) ) != 0 ) { DBG ( "Could not determine iBFT MAC: %s\n", strerror ( rc ) ); return rc; } - DBG ( "iBFT NIC MAC = %s\n", eth_ntoa ( nic->mac_address ) ); + DBG ( "iBFT NIC[%d] MAC = %s\n", + nic->header.index, eth_ntoa ( nic->mac_address ) ); nic->pci_bus_dev_func = cpu_to_le16 ( netdev->dev->desc.location ); - DBG ( "iBFT NIC PCI = %04x\n", le16_to_cpu ( nic->pci_bus_dev_func ) ); + DBG ( "iBFT NIC[%d] PCI = %04x\n", + nic->header.index, le16_to_cpu ( nic->pci_bus_dev_func ) ); if ( ( rc = ibft_set_string_setting ( NULL, strings, &nic->hostname, &hostname_setting ) ) != 0 ) return rc; - DBG ( "iBFT NIC hostname = %s\n", + DBG ( "iBFT NIC[%d] hostname = %s\n", + nic->header.index, ibft_string ( strings, &nic->hostname ) ); return 0; @@ -460,12 +511,14 @@ static int ibft_fill_target_chap ( struct ibft_target *target, if ( ( rc = ibft_set_string ( strings, &target->chap_name, iscsi->initiator_username ) ) != 0 ) return rc; - DBG ( "iBFT target username = %s\n", + DBG ( "iBFT target[%d] username = %s\n", + target->header.index, ibft_string ( strings, &target->chap_name ) ); if ( ( rc = ibft_set_string ( strings, &target->chap_secret, iscsi->initiator_password ) ) != 0 ) return rc; - DBG ( "iBFT target password = \n" ); + DBG ( "iBFT target[%d] password = \n", + target->header.index ); return 0; } @@ -495,12 +548,14 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target, if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_name, iscsi->target_username ) ) != 0 ) return rc; - DBG ( "iBFT target reverse username = %s\n", + DBG ( "iBFT target[%d] reverse username = %s\n", + target->header.index, ibft_string ( strings, &target->chap_name ) ); if ( ( rc = ibft_set_string ( strings, &target->reverse_chap_secret, iscsi->target_password ) ) != 0 ) return rc; - DBG ( "iBFT target reverse password = \n" ); + DBG ( "iBFT target[%d] reverse password = \n", + target->header.index ); return 0; } @@ -515,15 +570,29 @@ static int ibft_fill_target_reverse_chap ( struct ibft_target *target, */ static int ibft_fill_target ( struct ibft_target *target, struct ibft_strings *strings, - struct iscsi_session *iscsi ) { + struct iscsi_session *iscsi, + int ibft_index ) { struct sockaddr_in *sin_target = ( struct sockaddr_in * ) &iscsi->target_sockaddr; struct sockaddr_in6 *sin6_target = ( struct sockaddr_in6 * ) &iscsi->target_sockaddr; int rc; - if (sin6_target->sin6_family != AF_INET6 && - sin_target->sin_family != AF_INET) { + if (sin_target->sin_family == AF_INET) { + if (target->header.flags & IBFT_FL_TARGET_BLOCK_VALID) { + struct ibft_ipaddr tmp; + ibft_set_ipaddr ( &tmp, sin_target->sin_addr ); + if ( memcmp( &target->ip_address, &tmp, sizeof(tmp) )) + return -EBUSY; + } + } else if (sin6_target->sin6_family == AF_INET6) { + if (target->header.flags & IBFT_FL_TARGET_BLOCK_VALID) { + struct ibft_ipaddr tmp; + ibft_set_ip6addr ( &tmp, sin6_target->sin6_addr ); + if ( memcmp( &target->ip_address, &tmp, sizeof(tmp) )) + return -EBUSY; + } + } else { DBG ( "iBFT invalid IP address type %d\n", sin6_target->sin6_family ); return -EPROTONOSUPPORT; @@ -531,31 +600,35 @@ static int ibft_fill_target ( struct ibft_target *target, /* Fill in common header */ target->header.structure_id = IBFT_STRUCTURE_ID_TARGET; target->header.version = 1; + target->header.index = ibft_index; target->header.length = cpu_to_le16 ( sizeof ( *target ) ); target->header.flags = ( IBFT_FL_TARGET_BLOCK_VALID | IBFT_FL_TARGET_FIRMWARE_BOOT_SELECTED ); + target->nic_association = ibft_index; /* Fill in Target values */ if (sin_target->sin_family == AF_INET) { ibft_set_ipaddr ( &target->ip_address, sin_target->sin_addr ); - DBG ( "iBFT target IP = %s\n", + DBG ( "iBFT target[%d] IP = %s\n", target->header.index, ibft_ipaddr ( &target->ip_address ) ); target->socket = cpu_to_le16 ( ntohs ( sin_target->sin_port ) ); - DBG ( "iBFT target port = %d\n", target->socket ); + DBG ( "iBFT target[%d] port = %d\n", target->header.index, + target->socket ); } else { ibft_set_ip6addr ( &target->ip_address, sin6_target->sin6_addr ); - DBG ( "iBFT target IP = %s\n", + DBG ( "iBFT target[%d] IP = %s\n", target->header.index, ibft_ipaddr ( &target->ip_address ) ); target->socket = cpu_to_le16 ( ntohs ( sin6_target->sin6_port ) ); - DBG ( "iBFT target port = %d\n", target->socket ); + DBG ( "iBFT target[%d] port = %d\n", target->header.index, + target->socket ); } memcpy ( &target->boot_lun, &iscsi->lun, sizeof ( target->boot_lun ) ); - DBG ( "iBFT target boot LUN = " SCSI_LUN_FORMAT "\n", - SCSI_LUN_DATA ( target->boot_lun ) ); + DBG ( "iBFT target[%d] boot LUN = " SCSI_LUN_FORMAT "\n", + target->header.index, SCSI_LUN_DATA ( target->boot_lun ) ); if ( ( rc = ibft_set_string ( strings, &target->target_name, iscsi->target_iqn ) ) != 0 ) return rc; - DBG ( "iBFT target name = %s\n", + DBG ( "iBFT target[%d] name = %s\n", target->header.index, ibft_string ( strings, &target->target_name ) ); if ( ( rc = ibft_fill_target_chap ( target, strings, iscsi ) ) != 0 ) return rc; @@ -584,9 +657,12 @@ int ibft_describe ( struct iscsi_session *iscsi, .offset = offsetof ( typeof ( *ibft ), strings ), .len = len, }; + struct iscsi_session *tmp_iscsi; + int ibft_index = 0; int rc; /* Fill in ACPI header */ + DBG ( "iBFT table %p\n", ibft); ibft->table.acpi.signature = cpu_to_le32 ( IBFT_SIG ); ibft->table.acpi.length = cpu_to_le32 ( len ); ibft->table.acpi.revision = 1; @@ -599,20 +675,41 @@ int ibft_describe ( struct iscsi_session *iscsi, ibft->table.control.initiator = cpu_to_le16 ( offsetof ( typeof ( *ibft ), initiator ) ); ibft->table.control.nic_0 = - cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic ) ); + cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic0 ) ); ibft->table.control.target_0 = - cpu_to_le16 ( offsetof ( typeof ( *ibft ), target ) ); + cpu_to_le16 ( offsetof ( typeof ( *ibft ), target0 ) ); + ibft->table.control.nic_1 = + cpu_to_le16 ( offsetof ( typeof ( *ibft ), nic1 ) ); + ibft->table.control.target_1 = + cpu_to_le16 ( offsetof ( typeof ( *ibft ), target1 ) ); - /* Fill in NIC, Initiator and Target blocks */ - if ( ( rc = ibft_fill_nic ( &ibft->nic, &strings, - iscsi ) ) != 0 ) - return rc; + /* Fill in Initiator block */ if ( ( rc = ibft_fill_initiator ( &ibft->initiator, &strings, iscsi ) ) != 0 ) return rc; - if ( ( rc = ibft_fill_target ( &ibft->target, &strings, - iscsi ) ) != 0 ) - return rc; - return 0; + list_for_each_entry( tmp_iscsi, &iscsi_session_list, node ) { + struct ibft_nic *nic; + struct ibft_target *target; + + if ( ibft_index == 0 ) { + nic = &ibft->nic0; + target = &ibft->target0; + } else { + nic = &ibft->nic1; + target = &ibft->target1; + } + /* Fill in NIC blocks */ + rc = ibft_fill_nic ( nic, &strings, + tmp_iscsi, ibft_index ); + if (rc == 0) + /* Fill in target blocks */ + rc = ibft_fill_target ( target, &strings, tmp_iscsi, + ibft_index ); + if ( rc != 0 ) + break; + ibft_index++; + } + + return rc; } diff --git a/src/include/ipxe/iscsi.h b/src/include/ipxe/iscsi.h index c75ff41883..81c71c63f3 100644 --- a/src/include/ipxe/iscsi.h +++ b/src/include/ipxe/iscsi.h @@ -534,6 +534,9 @@ struct iscsi_session { /** Reference counter */ struct refcnt refcnt; + /** List of existing sessions */ + struct list_head node; + /** SCSI command-issuing interface */ struct interface control; /** SCSI command interface */ @@ -649,6 +652,9 @@ struct iscsi_session { struct scsi_lun lun; }; +/** iSCSI session list */ +extern struct list_head iscsi_session_list; + /** iSCSI session is currently in the security negotiation phase */ #define ISCSI_STATUS_SECURITY_NEGOTIATION_PHASE \ ( ISCSI_LOGIN_CSG_SECURITY_NEGOTIATION | \ diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index efb58cfe20..0a23341f0a 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -151,6 +151,8 @@ static void iscsi_start_login ( struct iscsi_session *iscsi ); static void iscsi_start_data_out ( struct iscsi_session *iscsi, unsigned int datasn ); +LIST_HEAD( iscsi_session_list ); + /** * Finish receiving PDU data into buffer * @@ -200,6 +202,7 @@ static void iscsi_free ( struct refcnt *refcnt ) { struct iscsi_session *iscsi = container_of ( refcnt, struct iscsi_session, refcnt ); + list_del ( &iscsi->node ); free ( iscsi->initiator_iqn ); free ( iscsi->target_address ); free ( iscsi->target_iqn ); @@ -2070,6 +2073,8 @@ static int iscsi_open ( struct interface *parent, struct uri *uri ) { rc = -ENOMEM; goto err_zalloc; } + INIT_LIST_HEAD( &iscsi->node); + list_add_tail ( &iscsi->node, &iscsi_session_list ); ref_init ( &iscsi->refcnt, iscsi_free ); intf_init ( &iscsi->control, &iscsi_control_desc, &iscsi->refcnt ); intf_init ( &iscsi->data, &iscsi_data_desc, &iscsi->refcnt ); From f358c106d015117e6da0f4b39535005c068ec67c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 8 May 2015 11:39:50 +0200 Subject: [PATCH 5/6] [dhcpv6] display 'dhcp6-server' setting DHCPv6 obviously has a server address, so we should make it available via a new 'dhcp6-server' setting. Signed-off-by: Hannes Reinecke --- src/include/ipxe/dhcpv6.h | 3 +++ src/include/ipxe/settings.h | 2 ++ src/net/udp/dhcpv6.c | 47 +++++++++++++++++++++++++++++++++++-- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/include/ipxe/dhcpv6.h b/src/include/ipxe/dhcpv6.h index 6e70f7e639..809a622aeb 100644 --- a/src/include/ipxe/dhcpv6.h +++ b/src/include/ipxe/dhcpv6.h @@ -178,6 +178,9 @@ struct dhcpv6_user_class_option { /** DHCPv6 client network interface identifier option */ #define DHCPV6_CLIENT_NDI 62 +/** DHCPv6 server address meta-option */ +#define DHCPV6_SERVER_ADDR 0xfffe + /** DHCPv6 syslog server option * * This option code has not yet been assigned by IANA. Please update diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 3cb4689197..95cb881f77 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -481,6 +481,8 @@ extern const struct setting board_serial_setting __setting ( SETTING_HOST_EXTRA, board-serial ); extern const struct setting dhcp_server_setting __setting ( SETTING_MISC, dhcp-server ); +extern const struct setting dhcp6_server_setting __setting ( SETTING_MISC, + dhcp6-server ); /** * Initialise a settings block diff --git a/src/net/udp/dhcpv6.c b/src/net/udp/dhcpv6.c index 253032e4e9..b7258fa7d0 100644 --- a/src/net/udp/dhcpv6.c +++ b/src/net/udp/dhcpv6.c @@ -268,6 +268,8 @@ struct dhcpv6_settings { struct settings settings; /** Leased address */ struct in6_addr lease; + /** Server address */ + struct in6_addr server; /** Option list */ struct dhcpv6_option_list options; }; @@ -310,6 +312,30 @@ static int dhcpv6_fetch_lease ( struct dhcpv6_settings *dhcpv6set, return sizeof ( *lease ); } +/** + * Fetch value of DHCPv6 server address + * + * @v dhcpset DHCPv6 settings + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int dhcpv6_fetch_server ( struct dhcpv6_settings *dhcpv6set, + void *data, size_t len ) { + struct in6_addr *server = &dhcpv6set->server; + + /* Do nothing unless a server address exists */ + if ( IN6_IS_ADDR_UNSPECIFIED ( server ) ) + return -ENOENT; + + /* Copy server address */ + if ( len > sizeof ( *server ) ) + len = sizeof ( *server ); + memcpy ( data, server, len ); + + return sizeof ( *server ); +} + /** * Fetch value of DHCPv6 setting * @@ -331,6 +357,10 @@ static int dhcpv6_fetch ( struct settings *settings, if ( setting_cmp ( setting, &ip6_setting ) == 0 ) return dhcpv6_fetch_lease ( dhcpv6set, data, len ); + /* Handle server address */ + if ( setting_cmp ( setting, &dhcp6_server_setting ) == 0 ) + return dhcpv6_fetch_server ( dhcpv6set, data, len ); + /* Find option */ option = dhcpv6_option ( &dhcpv6set->options, setting->tag ); if ( ! option ) @@ -359,6 +389,7 @@ static struct settings_operations dhcpv6_settings_operations = { * @ret rc Return status code */ static int dhcpv6_register ( struct in6_addr *lease, + struct in6_addr *server, struct dhcpv6_option_list *options, struct settings *parent ) { struct dhcpv6_settings *dhcpv6set; @@ -382,6 +413,7 @@ static int dhcpv6_register ( struct in6_addr *lease, dhcpv6set->options.data = data; dhcpv6set->options.len = len; memcpy ( &dhcpv6set->lease, lease, sizeof ( dhcpv6set->lease ) ); + memcpy ( &dhcpv6set->server, server, sizeof ( dhcpv6set->server ) ); /* Register settings */ if ( ( rc = register_settings ( &dhcpv6set->settings, parent, @@ -876,8 +908,8 @@ static int dhcpv6_rx ( struct dhcpv6_session *dhcpv6, } /* Register settings */ - if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &options, - parent ) ) != 0 ) { + if ( ( rc = dhcpv6_register ( &dhcpv6->lease, &src->sin6_addr, + &options, parent ) ) != 0 ) { DBGC ( dhcpv6, "DHCPv6 %s could not register settings: %s\n", dhcpv6->netdev->name, strerror ( rc ) ); goto done; @@ -1015,3 +1047,14 @@ const struct setting dnssl6_setting __setting ( SETTING_IP_EXTRA, dnssl ) = { .type = &setting_type_dnssl, .scope = &dhcpv6_scope, }; + +/** DHCPv6 server address */ +const struct setting dhcp6_server_setting __setting ( SETTING_MISC, + dhcp6-server ) = { + .name = "dhcp6-server", + .description = "DHCPv6 server", + .tag = DHCPV6_SERVER_ADDR, + .type = &setting_type_ipv6, + .scope = &dhcpv6_scope, +}; + From b7cef04c5624e891e0ffa1cc7f500c3dbf7f8db5 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 8 May 2015 12:16:43 +0200 Subject: [PATCH 6/6] [ibft] fill out 'dhcp' if applicable If the network address is received via DHCP/DHCPv6 the iBFT should fill out the 'dhcp' field with the address of the DHCP/DHCPv6 server. Signed-off-by: Hannes Reinecke --- src/drivers/block/ibft.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/drivers/block/ibft.c b/src/drivers/block/ibft.c index 75885285c8..bfa3ccbe38 100644 --- a/src/drivers/block/ibft.c +++ b/src/drivers/block/ibft.c @@ -290,14 +290,23 @@ static struct net_device *ibft_fill_nic_ipv4 ( struct ibft_nic *nic, parent = netdev_settings(route4->netdev); fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); - nic->origin = ( ( origin == parent ) ? - IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); + nic->origin = IBFT_NIC_ORIGIN_MANUAL; + /* Check if the IPv4 address originates from DHCP */ + if (strstr(settings_name(origin), "dhcp")) { + struct in_addr dhcp; + + nic->origin = IBFT_NIC_ORIGIN_DHCP; + if ( fetch_ipv4_setting( parent, &dhcp_server_setting, + &dhcp ) > 0 ) { + ibft_set_ipaddr ( &nic->dhcp, dhcp ); + DBG ( "iBFT NIC[%d] DHCP = %s\n", + nic->header.index, + ibft_ipaddr ( &nic->dhcp ) ); + } + } DBG ( "iBFT NIC[%d] origin = %d\n", nic->header.index, nic->origin ); - /* Extract values from configuration settings */ - fetch_setting ( parent, &ip_setting, &origin, NULL, NULL, 0 ); - ibft_set_ipaddr ( &nic->ip_address, route4->address ); DBG ( "iBFT NIC[%d] IP = %s\n", nic->header.index, ibft_ipaddr ( &nic->ip_address ) ); @@ -339,8 +348,20 @@ static struct net_device * ibft_fill_nic_ipv6 ( struct ibft_nic *nic, parent = netdev_settings(route6->netdev); fetch_setting ( parent, &ip6_setting, &origin, NULL, NULL, 0 ); - nic->origin = ( ( origin == parent ) ? - IBFT_NIC_ORIGIN_MANUAL : IBFT_NIC_ORIGIN_DHCP ); + nic->origin = IBFT_NIC_ORIGIN_MANUAL; + /* Check if the IPv6 address originates from DHCP */ + if (strstr(settings_name(origin), "dhcp")) { + struct in6_addr dhcp6; + + nic->origin = IBFT_NIC_ORIGIN_DHCP; + if ( fetch_ipv6_setting( parent, &dhcp6_server_setting, + &dhcp6 ) > 0 ) { + ibft_set_ip6addr(&nic->dhcp, dhcp6 ); + DBG ( "iBFT NIC[%d] DHCP = %s\n", + nic->header.index, + ibft_ipaddr ( &nic->dhcp ) ); + } + } DBG ( "iBFT NIC[%d] origin = %d\n", nic->header.index, nic->origin );