summaryrefslogtreecommitdiffstats
path: root/src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c')
-rw-r--r--src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c b/src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
new file mode 100644
index 0000000..4deef30
--- /dev/null
+++ b/src/roms/SLOF/clients/net-snk/app/netlib/dhcpv6.c
@@ -0,0 +1,216 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/udp.h>
+#include <netlib/dhcpv6.h>
+#include <netlib/tftp.h>
+#include <netlib/dns.h>
+
+static uint8_t tid[3];
+static uint32_t dhcpv6_state = -1;
+static filename_ip_t *my_fn_ip;
+
+static void
+generate_transaction_id(void)
+{
+ /* TODO: as per RFC 3315 transaction IDs should be generated randomly */
+ tid[0] = 1;
+ tid[1] = 2;
+ tid[2] = 4;
+}
+
+static void
+send_info_request(int fd)
+{
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ uint32_t payload_length;
+ struct dhcp_message_header *dhcph;
+
+ memset(ether_packet, 0, ETH_MTU_SIZE);
+
+ generate_transaction_id();
+
+ /* Get an IPv6 packet */
+ payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header);
+ fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
+ payload_length, IPTYPE_UDP,
+ get_ipv6_address(), &(all_dhcpv6_ll.addr));
+ fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr),
+ payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT);
+ dhcph = (struct dhcp_message_header *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr) +
+ sizeof(struct udphdr));
+
+ /* Fill in DHCPv6 data */
+ dhcph->type = DHCP_INFORMATION_REQUEST;
+ memcpy( &(dhcph->transaction_id), &tid, 3);
+ dhcph->option.client_id.code = DHCPV6_OPTION_CLIENTID;
+ dhcph->option.client_id.length = 10;
+ dhcph->option.client_id.duid_type = DUID_LL;
+ dhcph->option.client_id.hardware_type = 1;
+ memcpy( &(dhcph->option.client_id.mac),
+ get_mac_address(), 6);
+ dhcph->option.el_time.code = DHCPV6_OPTION_ELAPSED_TIME;
+ dhcph->option.el_time.length = 2;
+ dhcph->option.el_time.time = 0x190; /* 4000 ms */
+ dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO;
+ dhcph->option.option_request_option.length= 6;
+ dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS;
+ dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST;
+ dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL;
+
+
+ send_ipv6(fd, ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ethhdr)+ sizeof(struct ip6hdr)
+ + sizeof(struct udphdr)
+ + sizeof( struct dhcp_message_header) );
+}
+
+static int32_t
+dhcpv6_attempt(int fd)
+{
+ int sec;
+
+ // Send information request
+ send_info_request(fd);
+
+ dhcpv6_state = DHCPV6_STATE_SELECT;
+
+ // setting up a timer with a timeout of two seconds
+ for (sec = 0; sec < 2; sec++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether(fd);
+
+ // Wait until client will switch to Final state or Timeout occurs
+ switch (dhcpv6_state) {
+ case DHCP_STATUSCODE_SUCCESS:
+ return 1;
+ case DHCP_STATUSCODE_UNSPECFAIL: //FIXME
+ return 0;
+ }
+ } while (get_timer() > 0);
+ }
+
+ // timeout
+ return 0;
+}
+
+int32_t
+dhcpv6 ( char *ret_buffer, void *fn_ip)
+{
+ int fd;
+
+ my_fn_ip = (filename_ip_t *) fn_ip;
+ fd = my_fn_ip->fd;
+
+ if( !dhcpv6_attempt(fd)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct dhcp6_received_options *
+dhcp6_process_options (uint8_t *option, int32_t option_length)
+{
+ struct dhcp_boot_url *option_boot_url;
+ struct client_identifier *option_clientid;
+ struct server_identifier *option_serverid;
+ struct dhcp_dns *option_dns;
+ struct dhcp_dns_list *option_dns_list;
+ struct dhcp6_gen_option *option_gen;
+ struct dhcp6_received_options *received_options;
+ char buffer[256];
+
+
+ received_options = malloc (sizeof(struct dhcp6_received_options));
+ while (option_length > 0) {
+ switch ((uint16_t) *(option+1)) {
+ case DHCPV6_OPTION_CLIENTID:
+ option_clientid = (struct client_identifier *) option;
+ option = option + option_clientid->length + 4;
+ option_length = option_length - option_clientid->length - 4;
+ received_options->client_id = 1;
+ break;
+ case DHCPV6_OPTION_SERVERID:
+ option_serverid = (struct server_identifier *) option;
+ option = option + option_serverid->length + 4;
+ option_length = option_length - option_serverid->length - 4;
+ received_options->server_id = 1;
+ break;
+ case DHCPV6_OPTION_DNS_SERVERS:
+ option_dns = (struct dhcp_dns *) option;
+ option = option + option_dns->length + 4;
+ option_length = option_length - option_dns->length - 4;
+ memcpy( &(my_fn_ip->dns_ip6),
+ option_dns->p_ip6,
+ IPV6_ADDR_LENGTH);
+ dns_init(0, option_dns->p_ip6, 6);
+ break;
+ case DHCPV6_OPTION_DOMAIN_LIST:
+ option_dns_list = (struct dhcp_dns_list *) option;
+ option = option + option_dns_list->length + 4;
+ option_length = option_length - option_dns_list->length - 4;
+ break;
+ case DHCPV6_OPTION_BOOT_URL:
+ option_boot_url = (struct dhcp_boot_url *) option;
+ option = option + option_boot_url->length + 4;
+ option_length = option_length - option_boot_url->length - 4;
+ strncpy((char *)buffer,
+ (const char *)option_boot_url->url,
+ (size_t)option_boot_url->length);
+ buffer[option_boot_url->length] = 0;
+ if (parse_tftp_args(buffer,
+ (char *)my_fn_ip->server_ip6.addr,
+ (char *)my_fn_ip->filename,
+ (int)my_fn_ip->fd,
+ option_boot_url->length) == -1)
+ return NULL;
+ break;
+ default:
+ option_gen = (struct dhcp6_gen_option *) option;
+ option = option + option_gen->length + 4;
+ option_length = option_length - option_gen->length - 4;
+ }
+ }
+
+ return received_options;
+}
+
+uint32_t
+handle_dhcpv6(uint8_t * packet, int32_t packetsize)
+{
+
+ uint8_t *first_option;
+ int32_t option_length;
+ struct dhcp_message_reply *reply;
+ reply = (struct dhcp_message_reply *) packet;
+
+ if (reply->type == 7)
+ dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
+
+ first_option = packet + 4;
+ option_length = packet + packetsize - first_option;
+ dhcp6_process_options(first_option, option_length);
+
+ return 0;
+}
OpenPOWER on IntegriCloud