Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / clients / net-snk / app / netlib / dhcpv6.c
1 /******************************************************************************
2  * Copyright (c) 2013 IBM Corporation
3  * All rights reserved.
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
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <string.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <stdint.h>
17 #include <sys/socket.h>
18 #include <time.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>
25
26 static uint8_t tid[3];
27 static uint32_t dhcpv6_state = -1;
28 static filename_ip_t *my_fn_ip;
29
30 static void
31 generate_transaction_id(void)
32 {
33         /* TODO: as per RFC 3315 transaction IDs should be generated randomly */
34         tid[0] = 1;
35         tid[1] = 2;
36         tid[2] = 4;
37 }
38
39 static void
40 send_info_request(int fd)
41 {
42         uint8_t ether_packet[ETH_MTU_SIZE];
43         uint32_t payload_length;
44         struct dhcp_message_header *dhcph;
45
46         memset(ether_packet, 0, ETH_MTU_SIZE);
47
48         generate_transaction_id();
49
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));
61
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= 6;
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;
79
80
81         send_ipv6(fd, ether_packet + sizeof(struct ethhdr),
82                  sizeof(struct ethhdr)+ sizeof(struct ip6hdr)
83                  + sizeof(struct udphdr)
84                  + sizeof( struct dhcp_message_header) );
85 }
86
87 static int32_t
88 dhcpv6_attempt(int fd)
89 {
90         int sec;
91
92         // Send information request
93         send_info_request(fd);
94
95         dhcpv6_state = DHCPV6_STATE_SELECT;
96
97         // setting up a timer with a timeout of two seconds
98         for (sec = 0; sec < 2; sec++) {
99                 set_timer(TICKS_SEC);
100                 do {
101                         receive_ether(fd);
102
103                         // Wait until client will switch to Final state or Timeout occurs
104                         switch (dhcpv6_state) {
105                         case DHCP_STATUSCODE_SUCCESS:
106                                 return 1;
107                         case DHCP_STATUSCODE_UNSPECFAIL: //FIXME
108                                 return 0;
109                         }
110                 } while (get_timer() > 0);
111         }
112
113         // timeout
114         return 0;
115 }
116
117 int32_t
118 dhcpv6 ( char *ret_buffer, void *fn_ip)
119 {
120         int fd;
121
122         my_fn_ip = (filename_ip_t *) fn_ip;
123         fd = my_fn_ip->fd;
124
125         if( !dhcpv6_attempt(fd)) {
126                 return -1;
127         }
128
129         return 0;
130 }
131
132 static struct dhcp6_received_options *
133 dhcp6_process_options (uint8_t *option, int32_t option_length)
134 {
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;
141         struct dhcp6_received_options *received_options;
142         char buffer[256];
143
144
145         received_options = malloc (sizeof(struct dhcp6_received_options));
146         while (option_length > 0) {
147                 switch ((uint16_t) *(option+1)) {
148                 case DHCPV6_OPTION_CLIENTID:
149                         option_clientid = (struct client_identifier *) option;
150                         option = option +  option_clientid->length + 4;
151                         option_length = option_length - option_clientid->length - 4;
152                         received_options->client_id = 1;
153                         break;
154                 case DHCPV6_OPTION_SERVERID:
155                         option_serverid = (struct server_identifier *) option;
156                         option = option +  option_serverid->length + 4;
157                         option_length = option_length - option_serverid->length - 4;
158                         received_options->server_id = 1;
159                         break;
160                 case DHCPV6_OPTION_DNS_SERVERS:
161                         option_dns = (struct dhcp_dns *) option;
162                         option = option +  option_dns->length + 4;
163                         option_length = option_length - option_dns->length - 4;
164                         memcpy( &(my_fn_ip->dns_ip6),
165                                 option_dns->p_ip6,
166                                 IPV6_ADDR_LENGTH);
167                         dns_init(0, option_dns->p_ip6, 6);
168                         break;
169                 case DHCPV6_OPTION_DOMAIN_LIST:
170                         option_dns_list = (struct dhcp_dns_list *) option;
171                         option = option +  option_dns_list->length + 4;
172                         option_length = option_length - option_dns_list->length - 4;
173                         break;
174                 case DHCPV6_OPTION_BOOT_URL:
175                         option_boot_url = (struct dhcp_boot_url *) option;
176                         option = option +  option_boot_url->length + 4;
177                         option_length = option_length - option_boot_url->length - 4;
178                         strncpy((char *)buffer,
179                                 (const char *)option_boot_url->url,
180                                 (size_t)option_boot_url->length);
181                         buffer[option_boot_url->length] = 0;
182                         if (parse_tftp_args(buffer,
183                                             (char *)my_fn_ip->server_ip6.addr,
184                                             (char *)my_fn_ip->filename,
185                                             (int)my_fn_ip->fd,
186                                             option_boot_url->length) == -1)
187                                 return NULL;
188                         break;
189                 default:
190                         option_gen = (struct dhcp6_gen_option *) option;
191                         option = option + option_gen->length + 4;
192                         option_length = option_length - option_gen->length - 4;
193                 }
194         }
195
196         return received_options;
197 }
198
199 uint32_t
200 handle_dhcpv6(uint8_t * packet, int32_t packetsize)
201 {
202
203         uint8_t  *first_option;
204         int32_t option_length;
205         struct dhcp_message_reply *reply;
206         reply = (struct dhcp_message_reply *) packet;
207
208         if (reply->type == 7)
209                 dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
210
211         first_option =  packet + 4;
212         option_length =  packet + packetsize - first_option;
213         dhcp6_process_options(first_option, option_length);
214
215         return 0;
216 }