1 /******************************************************************************
2 * Copyright (c) 2013 IBM Corporation
4 * This program and the accompanying materials
5 * are made available under the terms of the BSD License
6 * which accompanies this distribution, and is available at
7 * http://www.opensource.org/licenses/bsd-license.php
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
17 #include <sys/socket.h>
19 #include <netlib/ethernet.h>
20 #include <netlib/ipv6.h>
21 #include <netlib/udp.h>
22 #include <netlib/dhcpv6.h>
23 #include <netlib/tftp.h>
24 #include <netlib/dns.h>
26 static uint8_t tid[3];
27 static uint32_t dhcpv6_state = -1;
28 static filename_ip_t *my_fn_ip;
30 static struct ip6addr_list_entry all_dhcpv6_ll; /* All DHCPv6 servers address */
33 dhcpv6_generate_transaction_id(void)
35 /* As per RFC 3315 transaction IDs should be generated randomly */
42 send_info_request(int fd)
44 uint8_t ether_packet[ETH_MTU_SIZE];
45 uint32_t payload_length;
46 struct dhcp_message_header *dhcph;
48 memset(ether_packet, 0, ETH_MTU_SIZE);
50 /* Get an IPv6 packet */
51 payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header);
52 fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
53 payload_length, IPTYPE_UDP,
54 get_ipv6_address(), &(all_dhcpv6_ll.addr));
55 fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr),
56 payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT);
57 dhcph = (struct dhcp_message_header *) (ether_packet +
58 sizeof(struct ethhdr) +
59 sizeof(struct ip6hdr) +
60 sizeof(struct udphdr));
62 /* Fill in DHCPv6 data */
63 dhcph->type = DHCP_INFORMATION_REQUEST;
64 memcpy( &(dhcph->transaction_id), &tid, 3);
65 dhcph->option.client_id.code = DHCPV6_OPTION_CLIENTID;
66 dhcph->option.client_id.length = 10;
67 dhcph->option.client_id.duid_type = DUID_LL;
68 dhcph->option.client_id.hardware_type = 1;
69 memcpy( &(dhcph->option.client_id.mac),
70 get_mac_address(), 6);
71 dhcph->option.el_time.code = DHCPV6_OPTION_ELAPSED_TIME;
72 dhcph->option.el_time.length = 2;
73 dhcph->option.el_time.time = 0x190; /* 4000 ms */
74 dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO;
75 dhcph->option.option_request_option.length = DHCPV6_OPTREQUEST_NUMOPTS * 2;
76 dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS;
77 dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST;
78 dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL;
80 send_ipv6(fd, ether_packet + sizeof(struct ethhdr),
81 sizeof(struct ip6hdr) + sizeof(struct udphdr)
82 + sizeof(struct dhcp_message_header));
86 dhcpv6_attempt(int fd)
90 // Send information request
91 send_info_request(fd);
93 dhcpv6_state = DHCPV6_STATE_SELECT;
95 // setting up a timer with a timeout of two seconds
96 for (sec = 0; sec < 2; sec++) {
101 // Wait until client will switch to Final state or Timeout occurs
102 switch (dhcpv6_state) {
103 case DHCP_STATUSCODE_SUCCESS:
105 case DHCP_STATUSCODE_UNSPECFAIL: //FIXME
108 } while (get_timer() > 0);
116 dhcpv6 ( char *ret_buffer, void *fn_ip)
120 all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL;
121 all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL;
123 my_fn_ip = (filename_ip_t *) fn_ip;
126 if( !dhcpv6_attempt(fd)) {
133 static void dhcp6_process_options (uint8_t *option, int32_t option_length)
135 struct dhcp_boot_url *option_boot_url;
136 struct client_identifier *option_clientid;
137 struct server_identifier *option_serverid;
138 struct dhcp_dns *option_dns;
139 struct dhcp_dns_list *option_dns_list;
140 struct dhcp6_gen_option *option_gen;
143 while (option_length > 0) {
144 switch ((uint16_t) *(option+1)) {
145 case DHCPV6_OPTION_CLIENTID:
146 option_clientid = (struct client_identifier *) option;
147 option = option + option_clientid->length + 4;
148 option_length = option_length - option_clientid->length - 4;
150 case DHCPV6_OPTION_SERVERID:
151 option_serverid = (struct server_identifier *) option;
152 option = option + option_serverid->length + 4;
153 option_length = option_length - option_serverid->length - 4;
155 case DHCPV6_OPTION_DNS_SERVERS:
156 option_dns = (struct dhcp_dns *) option;
157 option = option + option_dns->length + 4;
158 option_length = option_length - option_dns->length - 4;
159 memcpy( &(my_fn_ip->dns_ip6),
162 dns_init(0, option_dns->p_ip6, 6);
164 case DHCPV6_OPTION_DOMAIN_LIST:
165 option_dns_list = (struct dhcp_dns_list *) option;
166 option = option + option_dns_list->length + 4;
167 option_length = option_length - option_dns_list->length - 4;
169 case DHCPV6_OPTION_BOOT_URL:
170 option_boot_url = (struct dhcp_boot_url *) option;
171 option = option + option_boot_url->length + 4;
172 option_length = option_length - option_boot_url->length - 4;
173 strncpy((char *)buffer,
174 (const char *)option_boot_url->url,
175 (size_t)option_boot_url->length);
176 buffer[option_boot_url->length] = 0;
177 if (parse_tftp_args(buffer,
178 (char *)my_fn_ip->server_ip6.addr,
179 (char *)my_fn_ip->filename,
181 option_boot_url->length) == -1)
185 option_gen = (struct dhcp6_gen_option *) option;
186 option = option + option_gen->length + 4;
187 option_length = option_length - option_gen->length - 4;
193 handle_dhcpv6(uint8_t * packet, int32_t packetsize)
196 uint8_t *first_option;
197 int32_t option_length;
198 struct dhcp_message_reply *reply;
199 reply = (struct dhcp_message_reply *) packet;
201 if (memcmp(reply->transaction_id, tid, 3))
202 return -1; /* Wrong transaction ID */
204 if (reply->type == 7)
205 dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
207 first_option = packet + 4;
208 option_length = packet + packetsize - first_option;
209 dhcp6_process_options(first_option, option_length);