Blame iscsiuio/src/apps/dhcpc/dhcpv6.c

Packit eace71
/*
Packit eace71
 * Copyright (c) 2011, Broadcom Corporation
Packit eace71
 * Copyright (c) 2014, QLogic Corporation
Packit eace71
 *
Packit eace71
 * Written by:  Eddie Wai <eddie.wai@broadcom.com>
Packit eace71
 *              Based on code from Kevin Tran's iSCSI boot code
Packit eace71
 *
Packit eace71
 * All rights reserved.
Packit eace71
 *
Packit eace71
 * Redistribution and use in source and binary forms, with or without
Packit eace71
 * modification, are permitted provided that the following conditions
Packit eace71
 * are met:
Packit eace71
 * 1. Redistributions of source code must retain the above copyright
Packit eace71
 *    notice, this list of conditions and the following disclaimer.
Packit eace71
 * 2. Redistributions in binary form must reproduce the above copyright
Packit eace71
 *    notice, this list of conditions and the following disclaimer in the
Packit eace71
 *    documentation and/or other materials provided with the distribution.
Packit eace71
 * 3. All advertising materials mentioning features or use of this software
Packit eace71
 *    must display the following acknowledgement:
Packit eace71
 *      This product includes software developed by Adam Dunkels.
Packit eace71
 * 4. The name of the author may not be used to endorse or promote
Packit eace71
 *    products derived from this software without specific prior
Packit eace71
 *    written permission.
Packit eace71
 *
Packit eace71
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
Packit eace71
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit eace71
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit eace71
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
Packit eace71
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit eace71
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
Packit eace71
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
Packit eace71
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
Packit eace71
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
Packit eace71
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit eace71
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit eace71
 *
Packit eace71
 * dhcpv6.c - DHCPv6 engine
Packit eace71
 *
Packit eace71
 */
Packit eace71
#include <stdio.h>
Packit eace71
#include <string.h>
Packit eace71
Packit eace71
#include "ipv6.h"
Packit eace71
#include "ipv6_pkt.h"
Packit eace71
#include "dhcpv6.h"
Packit eace71
#include "logger.h"
Packit eace71
Packit eace71
/* Local function prototypes */
Packit eace71
static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context);
Packit eace71
static int dhcpv6_send_request_packet(struct dhcpv6_context *context);
Packit eace71
static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type);
Packit eace71
static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr);
Packit eace71
static void dhcpv6_handle_advertise(struct dhcpv6_context *context,
Packit eace71
				    u16_t dhcpv6_len);
Packit eace71
static void dhcpv6_handle_reply(struct dhcpv6_context *context,
Packit eace71
				u16_t dhcpv6_len);
Packit eace71
static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context,
Packit eace71
				    struct dhcpv6_opt_hdr *opt_hdr);
Packit eace71
static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context,
Packit eace71
					   struct dhcpv6_opt_hdr *opt_hdr);
Packit eace71
static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context,
Packit eace71
				       u8_t *option, int len);
Packit eace71
Packit eace71
void dhcpv6_init(struct dhcpv6_context *context)
Packit eace71
{
Packit eace71
	context->seconds = 0;
Packit eace71
	context->our_mac_addr =
Packit eace71
	    ipv6_get_link_addr(context->ipv6_context);
Packit eace71
Packit eace71
	/* Use the last four bytes of MAC address as base of the transaction
Packit eace71
	   ID */
Packit eace71
	context->dhcpv6_transaction_id = context->our_mac_addr->last_4_bytes;
Packit eace71
Packit eace71
	context->dhcpv6_done = FALSE;
Packit eace71
	strcpy(context->dhcp_vendor_id, "BRCM ISAN");
Packit eace71
}
Packit eace71
Packit eace71
int dhcpv6_do_discovery(struct dhcpv6_context *context)
Packit eace71
{
Packit eace71
	int retc = ISCSI_FAILURE;
Packit eace71
Packit eace71
	context->eth =
Packit eace71
	    (struct eth_hdr *)context->ipv6_context->ustack->data_link_layer;
Packit eace71
	context->ipv6 =
Packit eace71
	    (struct ipv6_hdr *)context->ipv6_context->ustack->network_layer;
Packit eace71
	context->udp =
Packit eace71
	    (struct udp_hdr *)((u8_t *)context->ipv6 + sizeof(struct ipv6_hdr));
Packit eace71
Packit eace71
	/* Send out DHCPv6 Solicit packet. */
Packit eace71
	dhcpv6_send_solicit_packet(context);
Packit eace71
Packit eace71
	return retc;
Packit eace71
}
Packit eace71
Packit eace71
static int dhcpv6_send_solicit_packet(struct dhcpv6_context *context)
Packit eace71
{
Packit eace71
	u16_t packet_len;
Packit eace71
Packit eace71
	LOG_DEBUG("DHCPV6: Send solicit");
Packit eace71
	packet_len = dhcpv6_init_packet(context, DHCPV6_SOLICIT);
Packit eace71
	context->dhcpv6_state = DHCPV6_STATE_SOLICIT_SENT;
Packit eace71
	ipv6_send_udp_packet(context->ipv6_context, packet_len);
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static int dhcpv6_send_request_packet(struct dhcpv6_context *context)
Packit eace71
{
Packit eace71
	u16_t packet_len;
Packit eace71
Packit eace71
	LOG_DEBUG("DHCPV6: Send request");
Packit eace71
	packet_len = dhcpv6_init_packet(context, DHCPV6_REQUEST);
Packit eace71
Packit eace71
	context->dhcpv6_state = DHCPV6_STATE_REQ_SENT;
Packit eace71
	ipv6_send_udp_packet(context->ipv6_context, packet_len);
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
static u16_t dhcpv6_init_packet(struct dhcpv6_context *context, u8_t type)
Packit eace71
{
Packit eace71
	u16_t pkt_len;
Packit eace71
	struct udp_hdr *udp = context->udp;
Packit eace71
	union dhcpv6_hdr *dhcpv6;
Packit eace71
	struct dhcpv6_option *opt;
Packit eace71
	u16_t len;
Packit eace71
Packit eace71
	/* Initialize dest IP with well-known DHCP server address */
Packit eace71
	dhcpv6_init_dhcpv6_server_addr(&context->ipv6->ipv6_dst);
Packit eace71
	/* Initialize dest MAC based on MC dest IP */
Packit eace71
	ipv6_mc_init_dest_mac(context->eth, context->ipv6);
Packit eace71
Packit eace71
	/* Initialize UDP header */
Packit eace71
	udp->src_port = HOST_TO_NET16(DHCPV6_CLIENT_PORT);
Packit eace71
	udp->dest_port = HOST_TO_NET16(DHCPV6_SERVER_PORT);
Packit eace71
Packit eace71
	/*
Packit eace71
	 * DHCPv6 section has the following format per RFC 3315
Packit eace71
	 *
Packit eace71
	 *  0                   1                   2                   3
Packit eace71
	 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
Packit eace71
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 * |    msg-type   |               transaction-id                  |
Packit eace71
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 * |                                                               |
Packit eace71
	 * .                            options                            .
Packit eace71
	 * .                           (variable)                          .
Packit eace71
	 * |                                                               |
Packit eace71
	 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 */
Packit eace71
	dhcpv6 = (union dhcpv6_hdr *)((u8_t *)udp + sizeof(struct udp_hdr));
Packit eace71
Packit eace71
	if (dhcpv6->dhcpv6_type != type)
Packit eace71
		context->dhcpv6_transaction_id++;
Packit eace71
Packit eace71
	dhcpv6->dhcpv6_trans_id = HOST_TO_NET16(context->dhcpv6_transaction_id);
Packit eace71
	dhcpv6->dhcpv6_type = type;
Packit eace71
Packit eace71
	/* Keep track of length of all DHCP options. */
Packit eace71
	pkt_len = sizeof(union dhcpv6_hdr);
Packit eace71
Packit eace71
	if (dhcpv6->dhcpv6_type == DHCPV6_REQUEST) {
Packit eace71
		/* We will send back whatever DHCPv6 sent us */
Packit eace71
		return ((u8_t *)udp - (u8_t *)context->eth +
Packit eace71
			NET_TO_HOST16(udp->length));
Packit eace71
	}
Packit eace71
Packit eace71
	opt = (struct dhcpv6_option *)((u8_t *)dhcpv6 +
Packit eace71
	      sizeof(union dhcpv6_hdr));
Packit eace71
	/* Add client ID option */
Packit eace71
	opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_CLIENTID);
Packit eace71
	opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_client_id));
Packit eace71
	opt->type.client_id.duid_type =
Packit eace71
	    HOST_TO_NET16(DHCPV6_DUID_TYPE_LINK_LAYER_AND_TIME);
Packit eace71
	opt->type.client_id.hw_type = HOST_TO_NET16(DHCPV6_HW_TYPE_ETHERNET);
Packit eace71
	opt->type.client_id.time = HOST_TO_NET32(clock_time()/1000 -
Packit eace71
						 0x3A4FC880);
Packit eace71
	memcpy((char *)&opt->type.client_id.link_layer_addr,
Packit eace71
	       (char *)context->our_mac_addr, sizeof(struct mac_address));
Packit eace71
	pkt_len += sizeof(struct dhcpv6_opt_client_id) +
Packit eace71
		   sizeof(struct dhcpv6_opt_hdr);
Packit eace71
	opt = (struct dhcpv6_option *)((u8_t *)opt +
Packit eace71
					sizeof(struct dhcpv6_opt_client_id) +
Packit eace71
					sizeof(struct dhcpv6_opt_hdr));
Packit eace71
Packit eace71
	/* Add Vendor Class option if it's configured */
Packit eace71
	len = strlen(context->dhcp_vendor_id);
Packit eace71
	if (len > 0) {
Packit eace71
		opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS);
Packit eace71
		opt->hdr.length =
Packit eace71
				HOST_TO_NET16(sizeof(struct dhcpv6_vendor_class)
Packit eace71
					      + len - 1);
Packit eace71
		opt->type.vendor_class.enterprise_number =
Packit eace71
		    HOST_TO_NET32(IANA_ENTERPRISE_NUM_BROADCOM);
Packit eace71
		opt->type.vendor_class.vendor_class_length = HOST_TO_NET16(len);
Packit eace71
		memcpy((char *)&opt->type.vendor_class.
Packit eace71
		       vendor_class_data[0],
Packit eace71
		       (char *)context->dhcp_vendor_id, len);
Packit eace71
		pkt_len +=
Packit eace71
		    sizeof(struct dhcpv6_vendor_class) - 1 + len +
Packit eace71
		    sizeof(struct dhcpv6_opt_hdr);
Packit eace71
		opt =
Packit eace71
		    (struct dhcpv6_option *)((u8_t *)opt +
Packit eace71
			      sizeof(struct dhcpv6_vendor_class) - 1 + len +
Packit eace71
			      sizeof(struct dhcpv6_opt_hdr));
Packit eace71
	}
Packit eace71
Packit eace71
	/* Add IA_NA option */
Packit eace71
	opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_IA_NA);
Packit eace71
	opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_id_assoc_na));
Packit eace71
	opt->type.ida_na.iaid = htonl(context->our_mac_addr->last_4_bytes);
Packit eace71
	opt->type.ida_na.t1 = 0;
Packit eace71
	opt->type.ida_na.t2 = 0;
Packit eace71
	pkt_len += sizeof(struct dhcpv6_opt_id_assoc_na) +
Packit eace71
		   sizeof(struct dhcpv6_opt_hdr);
Packit eace71
	opt = (struct dhcpv6_option *)((u8_t *)opt +
Packit eace71
					sizeof(struct dhcpv6_opt_id_assoc_na) +
Packit eace71
					sizeof(struct dhcpv6_opt_hdr));
Packit eace71
	/* Add Elapsed Time option */
Packit eace71
	opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ELAPSED_TIME);
Packit eace71
	opt->hdr.length = HOST_TO_NET16(sizeof(struct dhcpv6_opt_elapse_time));
Packit eace71
	opt->type.elapsed_time.time = HOST_TO_NET16(context->seconds);
Packit eace71
	pkt_len += sizeof(struct dhcpv6_opt_elapse_time) +
Packit eace71
		   sizeof(struct dhcpv6_opt_hdr);
Packit eace71
Packit eace71
	/* Add Option Request List */
Packit eace71
	opt = (struct dhcpv6_option *)((u8_t *)opt +
Packit eace71
					sizeof(struct dhcpv6_opt_elapse_time) +
Packit eace71
					sizeof(struct dhcpv6_opt_hdr));
Packit eace71
	opt->hdr.type = HOST_TO_NET16(DHCPV6_OPT_ORO);
Packit eace71
	opt->hdr.length = HOST_TO_NET16(3 *
Packit eace71
					sizeof(struct dhcpv6_opt_request_list));
Packit eace71
	opt->type.list.request_code[0] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_CLASS);
Packit eace71
	opt->type.list.request_code[1] = HOST_TO_NET16(DHCPV6_OPT_VENDOR_OPTS);
Packit eace71
	opt->type.list.request_code[2] = HOST_TO_NET16(DHCPV6_OPT_DNS_SERVERS);
Packit eace71
	pkt_len += 3 * sizeof(struct dhcpv6_opt_request_list) +
Packit eace71
		   sizeof(struct dhcpv6_opt_hdr);
Packit eace71
Packit eace71
	udp->length = HOST_TO_NET16(sizeof(struct udp_hdr) + pkt_len);
Packit eace71
Packit eace71
	pkt_len +=
Packit eace71
	    ((u8_t *)udp - (u8_t *)context->eth) + sizeof(struct udp_hdr);
Packit eace71
Packit eace71
	return pkt_len;
Packit eace71
}
Packit eace71
Packit eace71
static void dhcpv6_init_dhcpv6_server_addr(struct ipv6_addr *addr)
Packit eace71
{
Packit eace71
	/* Well-known DHCPv6 server address is ff02::1:2 */
Packit eace71
	memset((char *)addr, 0, sizeof(struct ipv6_addr));
Packit eace71
	addr->addr8[0] = 0xff;
Packit eace71
	addr->addr8[1] = 0x02;
Packit eace71
	addr->addr8[13] = 0x01;
Packit eace71
	addr->addr8[15] = 0x02;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_udp_handle_dhcp(struct dhcpv6_context *context)
Packit eace71
{
Packit eace71
	union dhcpv6_hdr *dhcpv6;
Packit eace71
	u16_t dhcpv6_len;
Packit eace71
Packit eace71
	if (context->dhcpv6_done == TRUE)
Packit eace71
		return;
Packit eace71
Packit eace71
	dhcpv6 = (union dhcpv6_hdr *)((u8_t *)context->udp +
Packit eace71
					sizeof(struct udp_hdr));
Packit eace71
Packit eace71
	if (dhcpv6->dhcpv6_trans_id !=
Packit eace71
	    HOST_TO_NET16(context->dhcpv6_transaction_id)) {
Packit eace71
		LOG_ERR("DHCPv6 transaction-id error, sent %x, received %x",
Packit eace71
			HOST_TO_NET16(context->dhcpv6_transaction_id),
Packit eace71
			dhcpv6->dhcpv6_trans_id);
Packit eace71
		return;
Packit eace71
	}
Packit eace71
Packit eace71
	dhcpv6_len =
Packit eace71
	    NET_TO_HOST16(context->udp->length) - sizeof(struct udp_hdr);
Packit eace71
Packit eace71
	switch (dhcpv6->dhcpv6_type) {
Packit eace71
	case DHCPV6_ADVERTISE:
Packit eace71
		dhcpv6_handle_advertise(context, dhcpv6_len);
Packit eace71
		break;
Packit eace71
Packit eace71
	case DHCPV6_REPLY:
Packit eace71
		dhcpv6_handle_reply(context, dhcpv6_len);
Packit eace71
		break;
Packit eace71
Packit eace71
	default:
Packit eace71
		break;
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static void dhcpv6_handle_advertise(struct dhcpv6_context *context,
Packit eace71
				    u16_t dhcpv6_len)
Packit eace71
{
Packit eace71
	union dhcpv6_hdr *dhcpv6 =
Packit eace71
	    (union dhcpv6_hdr *)((u8_t *)context->udp +
Packit eace71
				  sizeof(struct udp_hdr));
Packit eace71
	struct dhcpv6_opt_hdr *opt;
Packit eace71
	u16_t type;
Packit eace71
	int i;
Packit eace71
	int opt_len;
Packit eace71
	u8_t *vendor_id = NULL;
Packit eace71
	u16_t vendor_id_len = 0;
Packit eace71
	u8_t *vendor_opt_data = NULL;
Packit eace71
	int vendor_opt_len = 0;
Packit eace71
	int addr_cnt = 0;
Packit eace71
Packit eace71
	/* We only handle DHCPv6 advertise if we recently sent DHCPv6 solicit */
Packit eace71
	if (context->dhcpv6_state != DHCPV6_STATE_SOLICIT_SENT)
Packit eace71
		return;
Packit eace71
Packit eace71
	LOG_DEBUG("DHCPV6: handle advertise");
Packit eace71
	context->dhcpv6_state = DHCPV6_STATE_ADV_RCVD;
Packit eace71
Packit eace71
	i = 0;
Packit eace71
	while (i < (dhcpv6_len - sizeof(union dhcpv6_hdr))) {
Packit eace71
		opt = (struct dhcpv6_opt_hdr *)((u8_t *)dhcpv6 +
Packit eace71
						sizeof(union dhcpv6_hdr) + i);
Packit eace71
		opt_len = NET_TO_HOST16(opt->length);
Packit eace71
Packit eace71
		type = NET_TO_HOST16(opt->type);
Packit eace71
Packit eace71
		/* We only care about some of the options */
Packit eace71
		switch (type) {
Packit eace71
		case DHCPV6_OPT_IA_NA:
Packit eace71
			if (context->
Packit eace71
			    dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) {
Packit eace71
				addr_cnt +=
Packit eace71
				    dhcpv6_process_opt_ia_na(context, opt);
Packit eace71
			}
Packit eace71
			break;
Packit eace71
Packit eace71
		case DHCPV6_OPT_VENDOR_CLASS:
Packit eace71
			vendor_id_len =
Packit eace71
			    NET_TO_HOST16(((struct dhcpv6_option *)opt)->type.
Packit eace71
					  vendor_class.vendor_class_length);
Packit eace71
			vendor_id =
Packit eace71
			    &((struct dhcpv6_option *)opt)->type.vendor_class.
Packit eace71
			    vendor_class_data[0];
Packit eace71
			break;
Packit eace71
Packit eace71
		case DHCPV6_OPT_VENDOR_OPTS:
Packit eace71
			vendor_opt_len = opt_len - 4;
Packit eace71
			vendor_opt_data =
Packit eace71
			    &((struct dhcpv6_option *)opt)->type.vendor_opts.
Packit eace71
			    vendor_opt_data[0];
Packit eace71
			break;
Packit eace71
Packit eace71
		case DHCPV6_OPT_DNS_SERVERS:
Packit eace71
			if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS)
Packit eace71
				dhcpv6_process_opt_dns_servers(context, opt);
Packit eace71
			break;
Packit eace71
Packit eace71
		default:
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		i += NET_TO_HOST16(opt->length) + sizeof(struct dhcpv6_opt_hdr);
Packit eace71
	}
Packit eace71
Packit eace71
	if (context->dhcpv6_task & DHCPV6_TASK_GET_OTHER_PARAMS) {
Packit eace71
		if ((vendor_id_len > 0) &&
Packit eace71
		    (strncmp((char *)vendor_id,
Packit eace71
			     (char *)context->dhcp_vendor_id,
Packit eace71
			     vendor_id_len) == 0)) {
Packit eace71
			dhcpv6_parse_vendor_option(context,
Packit eace71
						   vendor_opt_data,
Packit eace71
						   vendor_opt_len);
Packit eace71
			context->dhcpv6_done = TRUE;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (context->dhcpv6_task & DHCPV6_TASK_GET_IP_ADDRESS) {
Packit eace71
		if (addr_cnt > 0) {
Packit eace71
			/*
Packit eace71
			 * If we need to acquire IP address from the server,
Packit eace71
			 * we need to send Request to server to confirm.
Packit eace71
			 */
Packit eace71
			dhcpv6_send_request_packet(context);
Packit eace71
			context->dhcpv6_done = TRUE;
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (context->dhcpv6_done) {
Packit eace71
		/* Keep track of IPv6 address of DHCHv6 server */
Packit eace71
		memcpy((char *)&context->dhcp_server,
Packit eace71
		       (char *)&context->ipv6->ipv6_src,
Packit eace71
		       sizeof(struct ipv6_addr));
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static int dhcpv6_process_opt_ia_na(struct dhcpv6_context *context,
Packit eace71
				    struct dhcpv6_opt_hdr *opt_hdr)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	int opt_len;
Packit eace71
	struct dhcpv6_option *opt;
Packit eace71
	int len;
Packit eace71
	int addr_cnt;
Packit eace71
	opt_len = NET_TO_HOST16(opt_hdr->length) -
Packit eace71
		  sizeof(struct dhcpv6_opt_id_assoc_na);
Packit eace71
Packit eace71
	i = 0;
Packit eace71
	addr_cnt = 0;
Packit eace71
	while (i < opt_len) {
Packit eace71
		opt =
Packit eace71
		    (struct dhcpv6_option *)((u8_t *)opt_hdr +
Packit eace71
				     sizeof(struct dhcpv6_opt_hdr) +
Packit eace71
				     sizeof(struct dhcpv6_opt_id_assoc_na) + i);
Packit eace71
Packit eace71
		len = NET_TO_HOST16(opt->hdr.length);
Packit eace71
		switch (NET_TO_HOST16(opt->hdr.type)) {
Packit eace71
		case DHCPV6_OPT_IAADDR:
Packit eace71
			if (len >
Packit eace71
			    (sizeof(struct dhcpv6_opt_hdr) +
Packit eace71
			     sizeof(struct dhcpv6_opt_iaa_addr))) {
Packit eace71
				struct dhcpv6_option *in_opt;
Packit eace71
Packit eace71
				in_opt = (struct dhcpv6_option *)((u8_t *)opt +
Packit eace71
					  sizeof(struct dhcpv6_opt_hdr) +
Packit eace71
					  sizeof(struct dhcpv6_opt_iaa_addr));
Packit eace71
				if (in_opt->hdr.type ==
Packit eace71
				    HOST_TO_NET16(DHCPV6_OPT_STATUS_CODE)) {
Packit eace71
					/* This entry has error! */
Packit eace71
					if (in_opt->type.sts.status != 0)
Packit eace71
						break;
Packit eace71
				}
Packit eace71
			}
Packit eace71
			LOG_INFO("DHCPv6: Got IP Addr");
Packit eace71
			/* Status is OK, let's add this addr to our address
Packit eace71
			   list */
Packit eace71
			ipv6_add_prefix_entry(context->ipv6_context,
Packit eace71
					      &opt->type.iaa_addr.addr, 64);
Packit eace71
Packit eace71
			/* Add multicast address for this address */
Packit eace71
			ipv6_add_solit_node_address(context->
Packit eace71
						    ipv6_context,
Packit eace71
						    &opt->type.iaa_addr.addr);
Packit eace71
			addr_cnt++;
Packit eace71
			break;
Packit eace71
Packit eace71
		default:
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		i += len + sizeof(struct dhcpv6_opt_hdr);
Packit eace71
	}
Packit eace71
Packit eace71
	return addr_cnt;
Packit eace71
}
Packit eace71
Packit eace71
static void dhcpv6_process_opt_dns_servers(struct dhcpv6_context *context,
Packit eace71
					   struct dhcpv6_opt_hdr *opt_hdr)
Packit eace71
{
Packit eace71
	int opt_len;
Packit eace71
Packit eace71
	opt_len = NET_TO_HOST16(opt_hdr->length);
Packit eace71
Packit eace71
	if (opt_len >= sizeof(struct ipv6_addr))
Packit eace71
		memcpy((char *)&context->primary_dns_server,
Packit eace71
		       (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns.
Packit eace71
				 primary_addr, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	if (opt_len >= 2 * sizeof(struct ipv6_addr))
Packit eace71
		memcpy((char *)&context->secondary_dns_server,
Packit eace71
		       (char *)&((struct dhcpv6_option *)opt_hdr)->type.dns.
Packit eace71
				 secondary_addr, sizeof(struct ipv6_addr));
Packit eace71
}
Packit eace71
Packit eace71
static void dhcpv6_handle_reply(struct dhcpv6_context *context,
Packit eace71
				u16_t dhcpv6_len)
Packit eace71
{
Packit eace71
	if (context->dhcpv6_state != DHCPV6_STATE_REQ_SENT)
Packit eace71
		return;
Packit eace71
Packit eace71
	context->dhcpv6_done = TRUE;
Packit eace71
}
Packit eace71
Packit eace71
static void dhcpv6_parse_vendor_option(struct dhcpv6_context *context,
Packit eace71
				       u8_t *option, int len)
Packit eace71
{
Packit eace71
	struct dhcpv6_option *opt;
Packit eace71
	u16_t type;
Packit eace71
	int opt_len;
Packit eace71
	int data_len;
Packit eace71
	int i;
Packit eace71
	u8_t *data;
Packit eace71
Packit eace71
	for (i = 0; i < len; i += opt_len + sizeof(struct dhcpv6_opt_hdr)) {
Packit eace71
		opt = (struct dhcpv6_option *)((u8_t *)option + i);
Packit eace71
		type = HOST_TO_NET16(opt->hdr.type);
Packit eace71
		opt_len = HOST_TO_NET16(opt->hdr.length);
Packit eace71
		data = &opt->type.data[0];
Packit eace71
		data_len = strlen((char *)data);
Packit eace71
Packit eace71
		switch (type) {
Packit eace71
		case 201:
Packit eace71
			/* iSCSI target 1 */
Packit eace71
			break;
Packit eace71
Packit eace71
		case 202:
Packit eace71
			/* iSCSI target 2 */
Packit eace71
			break;
Packit eace71
Packit eace71
		case 203:
Packit eace71
			if (data_len > ISCSI_MAX_ISCSI_NAME_LENGTH)
Packit eace71
				data_len = ISCSI_MAX_ISCSI_NAME_LENGTH;
Packit eace71
			data[data_len] = '\0';
Packit eace71
			strcpy(context->initiatorName, (char *)data);
Packit eace71
			break;
Packit eace71
Packit eace71
		default:
Packit eace71
			break;
Packit eace71
		}
Packit eace71
	}
Packit eace71
}