Blame iscsiuio/src/uip/ipv6.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 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
 * ipv6.c - This file contains simplifed IPv6 processing code.
Packit eace71
 *
Packit eace71
 */
Packit eace71
#include <stdio.h>
Packit eace71
#include <string.h>
Packit eace71
#include <arpa/inet.h>
Packit eace71
#include "logger.h"
Packit eace71
#include "uip.h"
Packit eace71
#include "ipv6.h"
Packit eace71
#include "ipv6_pkt.h"
Packit eace71
#include "icmpv6.h"
Packit eace71
#include "uipopt.h"
Packit eace71
#include "dhcpv6.h"
Packit eace71
#include "ping.h"
Packit eace71
Packit eace71
static inline int best_match_bufcmp(u8_t *a, u8_t *b, int len)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
Packit eace71
	for (i = 0; i < len; i++) {
Packit eace71
		if (a[i] != b[i])
Packit eace71
			break;
Packit eace71
	}
Packit eace71
	return i;
Packit eace71
}
Packit eace71
Packit eace71
/* Local function prototypes */
Packit eace71
static int ipv6_is_it_our_address(struct ipv6_context *context,
Packit eace71
				  struct ipv6_addr *ip_addr);
Packit eace71
static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6);
Packit eace71
static void ipv6_update_arp_table(struct ipv6_context *context,
Packit eace71
				  struct ipv6_addr *ip_addr,
Packit eace71
				  struct mac_address *mac_addr);
Packit eace71
static void ipv6_icmp_init_link_option(struct ipv6_context *context,
Packit eace71
				       struct icmpv6_opt_link_addr *link_opt,
Packit eace71
				       u8_t type);
Packit eace71
static void ipv6_icmp_rx(struct ipv6_context *context);
Packit eace71
static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context);
Packit eace71
static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context);
Packit eace71
static void ipv6_icmp_handle_echo_request(struct ipv6_context *context);
Packit eace71
static void ipv6_icmp_handle_router_adv(struct ipv6_context *context);
Packit eace71
static void ipv6_icmp_process_prefix(struct ipv6_context *context,
Packit eace71
				     struct icmpv6_opt_prefix *icmp_prefix);
Packit eace71
static void ipv6_udp_rx(struct ipv6_context *context);
Packit eace71
Packit eace71
int iscsiL2Send(struct ipv6_context *context, int pkt_len)
Packit eace71
{
Packit eace71
	LOG_DEBUG("IPv6: iscsiL2Send");
Packit eace71
	uip_send(context->ustack,
Packit eace71
		 (void *)context->ustack->data_link_layer, pkt_len);
Packit eace71
Packit eace71
	return pkt_len;
Packit eace71
}
Packit eace71
Packit eace71
int iscsiL2AddMcAddr(struct ipv6_context *context,
Packit eace71
		     struct mac_address *new_mc_addr)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	struct mac_address *mc_addr;
Packit eace71
	const struct mac_address all_zeroes_mc = { { { 0, 0, 0, 0, 0, 0 } } };
Packit eace71
Packit eace71
	mc_addr = context->mc_addr;
Packit eace71
	for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
Packit eace71
		if (!memcmp((char *)mc_addr,
Packit eace71
			    (char *)new_mc_addr, sizeof(struct mac_address)))
Packit eace71
			return TRUE;	/* Already in the mc table */
Packit eace71
Packit eace71
	mc_addr = context->mc_addr;
Packit eace71
	for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++) {
Packit eace71
		if (!memcmp((char *)mc_addr,
Packit eace71
		    (char *)&all_zeroes_mc, sizeof(struct mac_address))) {
Packit eace71
			memcpy((char *)mc_addr,
Packit eace71
			       (char *)new_mc_addr, sizeof(struct mac_address));
Packit eace71
			LOG_DEBUG("IPv6: mc_addr added "
Packit eace71
				  "%02x:%02x:%02x:%02x:%02x:%02x",
Packit eace71
				  *(u8_t *)new_mc_addr,
Packit eace71
				  *((u8_t *)new_mc_addr + 1),
Packit eace71
				  *((u8_t *)new_mc_addr + 2),
Packit eace71
				  *((u8_t *)new_mc_addr + 3),
Packit eace71
				  *((u8_t *)new_mc_addr + 4),
Packit eace71
				  *((u8_t *)new_mc_addr + 5));
Packit eace71
			return TRUE;
Packit eace71
		}
Packit eace71
	}
Packit eace71
	return FALSE;
Packit eace71
}
Packit eace71
Packit eace71
int iscsiL2IsOurMcAddr(struct ipv6_context *context,
Packit eace71
		       struct mac_address *dest_mac)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	struct mac_address *mc_addr;
Packit eace71
Packit eace71
	mc_addr = context->mc_addr;
Packit eace71
	for (i = 0; i < MAX_MCADDR_TABLE; i++, mc_addr++)
Packit eace71
		if (!memcmp((char *)mc_addr,
Packit eace71
			    (char *)dest_mac->addr, sizeof(struct mac_address)))
Packit eace71
			return TRUE;
Packit eace71
	return FALSE;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_init(struct ndpc_state *ndp, int cfg)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	struct ipv6_context *context = (struct ipv6_context *)ndp->ipv6_context;
Packit eace71
	struct mac_address *mac_addr = (struct mac_address *)ndp->mac_addr;
Packit eace71
	struct ipv6_arp_entry *ipv6_arp_table;
Packit eace71
	struct ipv6_prefix_entry *ipv6_prefix_table;
Packit eace71
	struct mac_address mc_addr;
Packit eace71
Packit eace71
	if (context == NULL) {
Packit eace71
		LOG_ERR("IPV6: INIT ipv6_context is NULL");
Packit eace71
		return;
Packit eace71
	}
Packit eace71
Packit eace71
	memset((char *)context, 0, sizeof(struct ipv6_context));
Packit eace71
Packit eace71
	/* Associate the nic_iface's ustack to this ipv6_context */
Packit eace71
	context->ustack = ndp->ustack;
Packit eace71
Packit eace71
	ipv6_arp_table = &context->ipv6_arp_table[0];
Packit eace71
	ipv6_prefix_table = &context->ipv6_prefix_table[0];
Packit eace71
Packit eace71
	memset((char *)ipv6_arp_table, 0, sizeof(*ipv6_arp_table));
Packit eace71
	memset((char *)ipv6_prefix_table, 0, sizeof(*ipv6_prefix_table));
Packit eace71
	memcpy((char *)&context->mac_addr,
Packit eace71
	       (char *)mac_addr, sizeof(struct mac_address));
Packit eace71
	/*
Packit eace71
	 * Per RFC 2373.
Packit eace71
	 * There are two types of local-use unicast addresses defined.  These
Packit eace71
	 * are Link-Local and Site-Local.  The Link-Local is for use on a single
Packit eace71
	 * link and the Site-Local is for use in a single site.  Link-Local
Packit eace71
	 * addresses have the following format:
Packit eace71
	 *
Packit eace71
	 * |   10     |
Packit eace71
	 * |  bits    |        54 bits          |          64 bits           |
Packit eace71
	 * +----------+-------------------------+----------------------------+
Packit eace71
	 * |1111111010|           0             |       interface ID         |
Packit eace71
	 * +----------+-------------------------+----------------------------+
Packit eace71
	 */
Packit eace71
	if (context->ustack->linklocal_autocfg != IPV6_LL_AUTOCFG_OFF) {
Packit eace71
		context->link_local_addr.addr8[0] = 0xfe;
Packit eace71
		context->link_local_addr.addr8[1] = 0x80;
Packit eace71
		/* Bit 1 is 1 to indicate universal scope. */
Packit eace71
		context->link_local_addr.addr8[8] = mac_addr->addr[0] | 0x2;
Packit eace71
		context->link_local_addr.addr8[9] = mac_addr->addr[1];
Packit eace71
		context->link_local_addr.addr8[10] = mac_addr->addr[2];
Packit eace71
		context->link_local_addr.addr8[11] = 0xff;
Packit eace71
		context->link_local_addr.addr8[12] = 0xfe;
Packit eace71
		context->link_local_addr.addr8[13] = mac_addr->addr[3];
Packit eace71
		context->link_local_addr.addr8[14] = mac_addr->addr[4];
Packit eace71
		context->link_local_addr.addr8[15] = mac_addr->addr[5];
Packit eace71
Packit eace71
		context->link_local_multi.addr8[0] = 0xff;
Packit eace71
		context->link_local_multi.addr8[1] = 0x02;
Packit eace71
		context->link_local_multi.addr8[11] = 0x01;
Packit eace71
		context->link_local_multi.addr8[12] = 0xff;
Packit eace71
		context->link_local_multi.addr8[13] |=
Packit eace71
		    context->link_local_addr.addr8[13];
Packit eace71
		context->link_local_multi.addr16[7] =
Packit eace71
		    context->link_local_addr.addr16[7];
Packit eace71
Packit eace71
		/* Default Prefix length is 64 */
Packit eace71
		/* Add Link local address to the head of the ipv6 address
Packit eace71
		   list */
Packit eace71
		ipv6_add_prefix_entry(context,
Packit eace71
				      &context->link_local_addr, 64);
Packit eace71
	}
Packit eace71
	/*
Packit eace71
	 * Convert Multicast IP address to Multicast MAC adress per
Packit eace71
	 * RFC 2464: Transmission of IPv6 Packets over Ethernet Networks
Packit eace71
	 *
Packit eace71
	 * An IPv6 packet with a multicast destination address DST, consisting
Packit eace71
	 * of the sixteen octets DST[1] through DST[16], is transmitted to the
Packit eace71
	 * Ethernet multicast address whose first two octets are the value 3333
Packit eace71
	 * hexadecimal and whose last four octets are the last four octets of
Packit eace71
	 * DST.
Packit eace71
	 *
Packit eace71
	 *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *          |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
Packit eace71
	 *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *          |   DST[13]     |   DST[14]     |
Packit eace71
	 *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *          |   DST[15]     |   DST[16]     |
Packit eace71
	 *          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *
Packit eace71
	 * IPv6 requires the following Multicast IP addresses setup per node.
Packit eace71
	 */
Packit eace71
	for (i = 0; i < 3; i++) {
Packit eace71
		mc_addr.addr[0] = 0x33;
Packit eace71
		mc_addr.addr[1] = 0x33;
Packit eace71
		mc_addr.addr[2] = 0x0;
Packit eace71
		mc_addr.addr[3] = 0x0;
Packit eace71
		mc_addr.addr[4] = 0x0;
Packit eace71
Packit eace71
		switch (i) {
Packit eace71
		case 0:
Packit eace71
			/* All Nodes Multicast IPv6 address : ff02::1 */
Packit eace71
			mc_addr.addr[5] = 0x1;
Packit eace71
			break;
Packit eace71
Packit eace71
		case 1:
Packit eace71
			/* All Host Multicast IPv6 address : ff02::3 */
Packit eace71
			mc_addr.addr[5] = 0x3;
Packit eace71
			break;
Packit eace71
Packit eace71
		case 2:
Packit eace71
			/* Solicited Node Multicast Address: ff02::01:ffxx:yyzz
Packit eace71
			 */
Packit eace71
			mc_addr.addr[2] = 0xff;
Packit eace71
			mc_addr.addr[3] = mac_addr->addr[3];
Packit eace71
			mc_addr.addr[4] = mac_addr->addr[4];
Packit eace71
			mc_addr.addr[5] = mac_addr->addr[5];
Packit eace71
			break;
Packit eace71
Packit eace71
		default:
Packit eace71
			break;
Packit eace71
		}
Packit eace71
		iscsiL2AddMcAddr(context, &mc_addr);
Packit eace71
	}
Packit eace71
Packit eace71
	/* Default HOP number */
Packit eace71
	context->hop_limit = IPV6_HOP_LIMIT;
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_add_prefix_entry(struct ipv6_context *context,
Packit eace71
			  struct ipv6_addr *ip_addr, u8_t prefix_len)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	struct ipv6_prefix_entry *prefix_entry;
Packit eace71
	struct ipv6_prefix_entry *ipv6_prefix_table =
Packit eace71
				  context->ipv6_prefix_table;
Packit eace71
	char addr_str[INET6_ADDRSTRLEN];
Packit eace71
Packit eace71
	/* Check if there is an valid entry already. */
Packit eace71
	for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
Packit eace71
		prefix_entry = &ipv6_prefix_table[i];
Packit eace71
Packit eace71
		if (prefix_entry->prefix_len != 0) {
Packit eace71
			if (memcmp((char *)&prefix_entry->ip_addr,
Packit eace71
				   (char *)ip_addr,
Packit eace71
				   sizeof(struct ipv6_addr)) == 0) {
Packit eace71
				/* We already initialize on this interface.
Packit eace71
				   There is nothing to do */
Packit eace71
				return 0;
Packit eace71
			}
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	/* Find an unused entry */
Packit eace71
	for (i = 0; i < IPV6_NUM_OF_ADDRESS_ENTRY; i++) {
Packit eace71
		prefix_entry = &ipv6_prefix_table[i];
Packit eace71
Packit eace71
		if (prefix_entry->prefix_len == 0)
Packit eace71
			break;
Packit eace71
	}
Packit eace71
Packit eace71
	if (prefix_entry->prefix_len != 0)
Packit eace71
		return -1;
Packit eace71
Packit eace71
	prefix_entry->prefix_len = prefix_len / 8;
Packit eace71
Packit eace71
	memcpy((char *)&prefix_entry->ip_addr,
Packit eace71
	       (char *)ip_addr, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	inet_ntop(AF_INET6, &prefix_entry->ip_addr.addr8, addr_str,
Packit eace71
		  sizeof(addr_str));
Packit eace71
Packit eace71
	LOG_DEBUG("IPv6: add prefix IP addr %s", addr_str);
Packit eace71
Packit eace71
	/* Put it on the list on head of the list. */
Packit eace71
	if (context->addr_list != NULL)
Packit eace71
		prefix_entry->next = context->addr_list;
Packit eace71
	else
Packit eace71
		prefix_entry->next = NULL;
Packit eace71
Packit eace71
	context->addr_list = prefix_entry;
Packit eace71
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_rx_packet(struct ipv6_context *context, u16_t len)
Packit eace71
{
Packit eace71
	struct ipv6_hdr *ipv6;
Packit eace71
	u16_t protocol;
Packit eace71
Packit eace71
	if (!context->ustack) {
Packit eace71
		LOG_WARN("ipv6 rx pkt ipv6_context = %p ustack = %p", context,
Packit eace71
			 context->ustack);
Packit eace71
		return;
Packit eace71
	}
Packit eace71
	ipv6 = (struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	/* Make sure it's an IPv6 packet */
Packit eace71
	if ((ipv6->ipv6_version_fc & 0xf0) != IPV6_VERSION) {
Packit eace71
		/* It's not an IPv6 packet. Drop it. */
Packit eace71
		LOG_WARN("IPv6 version 0x%x not IPv6", ipv6->ipv6_version_fc);
Packit eace71
		return;
Packit eace71
	}
Packit eace71
	protocol = ipv6_process_rx(ipv6);
Packit eace71
Packit eace71
	switch (protocol) {
Packit eace71
	case IPPROTO_ICMPV6:
Packit eace71
		ipv6_icmp_rx(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	case IPPROTO_UDP:
Packit eace71
		/* Indicate to UDP processing code */
Packit eace71
		ipv6_udp_rx(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	default:
Packit eace71
		break;
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_mc_init_dest_mac(struct eth_hdr *eth, struct ipv6_hdr *ipv6)
Packit eace71
{
Packit eace71
	int i;
Packit eace71
	/*
Packit eace71
	 * Initialize address mapping of IPV6 Multicast to multicast MAC
Packit eace71
	 * address per RFC 2464.
Packit eace71
	 *
Packit eace71
	 * An IPv6 packet with a multicast destination address DST, consisting
Packit eace71
	 * of the sixteen octets DST[1] through DST[16], is transmitted to the
Packit eace71
	 * Ethernet multicast address whose first two octets are the value 3333
Packit eace71
	 * hexadecimal and whose last four octets are the last four octets of
Packit eace71
	 * DST.
Packit eace71
	 *
Packit eace71
	 *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *              |0 0 1 1 0 0 1 1|0 0 1 1 0 0 1 1|
Packit eace71
	 *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *              |   DST[13]     |   DST[14]     |
Packit eace71
	 *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 *              |   DST[15]     |   DST[16]     |
Packit eace71
	 *              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Packit eace71
	 */
Packit eace71
	eth->dest_mac.addr[0] = 0x33;
Packit eace71
	eth->dest_mac.addr[1] = 0x33;
Packit eace71
	for (i = 0; i < 4; i++)
Packit eace71
		eth->dest_mac.addr[2 + i] = ipv6->ipv6_dst.addr8[12 + i];
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_autoconfig(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	return ipv6_discover_address(context);
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_discover_address(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	int rc = 0;
Packit eace71
Packit eace71
	/* Retrieve tx buffer */
Packit eace71
	if (eth == NULL || ipv6 == NULL)
Packit eace71
		return -EAGAIN;
Packit eace71
Packit eace71
	/* Setup IPv6 All Routers Multicast address : ff02::2 */
Packit eace71
	memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr));
Packit eace71
	ipv6->ipv6_dst.addr8[0] = 0xff;
Packit eace71
	ipv6->ipv6_dst.addr8[1] = 0x02;
Packit eace71
	ipv6->ipv6_dst.addr8[15] = 0x02;
Packit eace71
	ipv6->ipv6_hop_limit = 255;
Packit eace71
Packit eace71
	/* Initialize MAC header based on destination MAC address */
Packit eace71
	ipv6_mc_init_dest_mac(eth, ipv6);
Packit eace71
	ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
Packit eace71
Packit eace71
	icmp->icmpv6_type = ICMPV6_RTR_SOL;
Packit eace71
	icmp->icmpv6_code = 0;
Packit eace71
	icmp->icmpv6_data = 0;
Packit eace71
	icmp->icmpv6_cksum = 0;
Packit eace71
	ipv6_icmp_init_link_option(context,
Packit eace71
				   (struct icmpv6_opt_link_addr *)((u8_t *)icmp
Packit eace71
					+ sizeof(struct icmpv6_hdr)),
Packit eace71
					IPV6_ICMP_OPTION_SRC_ADDR);
Packit eace71
	ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
Packit eace71
					 sizeof(struct icmpv6_opt_link_addr)));
Packit eace71
	memcpy((char *)&ipv6->ipv6_src,
Packit eace71
	       (char *)&context->link_local_addr,
Packit eace71
	       sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	icmp->icmpv6_cksum = 0;
Packit eace71
	LOG_DEBUG("IPv6: Send rtr sol");
Packit eace71
	ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
Packit eace71
		  sizeof(struct icmpv6_hdr) +
Packit eace71
		  sizeof(struct icmpv6_opt_link_addr));
Packit eace71
	return rc;
Packit eace71
}
Packit eace71
Packit eace71
u16_t ipv6_process_rx(struct ipv6_hdr *ipv6)
Packit eace71
{
Packit eace71
	return ipv6->ipv6_nxt_hdr;
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_send(struct ipv6_context *context, u16_t packet_len)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
Packit eace71
	ipv6_setup_hdrs(context, eth, ipv6, packet_len);
Packit eace71
Packit eace71
	return iscsiL2Send(context, packet_len);
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_send_udp_packet(struct ipv6_context *context, u16_t packet_len)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
Packit eace71
						 sizeof(struct ipv6_hdr));
Packit eace71
Packit eace71
	ipv6->ipv6_nxt_hdr = IPPROTO_UDP;
Packit eace71
	ipv6->ipv6_plen =
Packit eace71
	    HOST_TO_NET16(packet_len - ((u8_t *)udp - (u8_t *)eth));
Packit eace71
Packit eace71
	udp->chksum = 0;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * We only use UDP packet for DHCPv6.  The source address is always
Packit eace71
	 * link-local address.
Packit eace71
	 */
Packit eace71
	ipv6->ipv6_src.addr[0] = 0;
Packit eace71
Packit eace71
	/* Hop limit is always 1 for DHCPv6 packet. */
Packit eace71
	ipv6->ipv6_hop_limit = 1;
Packit eace71
Packit eace71
	ipv6_send(context, packet_len);
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_setup_hdrs(struct ipv6_context *context, struct eth_hdr *eth,
Packit eace71
		     struct ipv6_hdr *ipv6, u16_t packet_len)
Packit eace71
{
Packit eace71
	struct ipv6_addr *our_address;
Packit eace71
Packit eace71
	/* VLAN will be taken cared of in the nic layer */
Packit eace71
	eth->len_type = HOST_TO_NET16(LAYER2_TYPE_IPV6);
Packit eace71
	memcpy((char *)&eth->src_mac,
Packit eace71
	       (char *)&context->mac_addr, sizeof(struct mac_address));
Packit eace71
Packit eace71
	/* Put the traffic class into the packet. */
Packit eace71
	memset(&ipv6->ipv6_version_fc, 0, sizeof(u32_t));
Packit eace71
	ipv6->ipv6_version_fc = IPV6_VERSION;
Packit eace71
	if (ipv6->ipv6_hop_limit == 0)
Packit eace71
		ipv6->ipv6_hop_limit = context->hop_limit;
Packit eace71
Packit eace71
	if (ipv6->ipv6_src.addr[0] == 0) {
Packit eace71
		/* Need to initialize source IP address. */
Packit eace71
		our_address = ipv6_our_address(context);
Packit eace71
		if (our_address != NULL) {
Packit eace71
			/* Assume that caller has filled in the destination
Packit eace71
			   IP address */
Packit eace71
			memcpy((char *)&ipv6->ipv6_src,
Packit eace71
			       (char *)our_address, sizeof(struct ipv6_addr));
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	ipv6_insert_protocol_chksum(ipv6);
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_insert_protocol_chksum(struct ipv6_hdr *ipv6)
Packit eace71
{
Packit eace71
	u32_t sum;
Packit eace71
	u16_t *ptr;
Packit eace71
	u16_t *protocol_data_ptr;
Packit eace71
	int i;
Packit eace71
	u16_t protocol_data_len;
Packit eace71
	u16_t checksum;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * This routine assumes that there is no extension header. This driver
Packit eace71
	 * doesn't user extension header to keep driver small and simple.
Packit eace71
	 *
Packit eace71
	 * Pseudo check consists of the following:
Packit eace71
	 * SRC IP, DST IP, Protocol Data Length, and Next Header.
Packit eace71
	 */
Packit eace71
	sum = 0;
Packit eace71
	ptr = (u16_t *)&ipv6->ipv6_src;
Packit eace71
Packit eace71
	for (i = 0; i < sizeof(struct ipv6_addr); i += 2) {
Packit eace71
		sum += HOST_TO_NET16(*ptr);
Packit eace71
		ptr++;
Packit eace71
	}
Packit eace71
Packit eace71
	/* Keep track where the layer header is */
Packit eace71
	protocol_data_ptr = ptr;
Packit eace71
Packit eace71
	protocol_data_len = HOST_TO_NET16(ipv6->ipv6_plen);
Packit eace71
	sum += protocol_data_len;
Packit eace71
	sum += ipv6->ipv6_nxt_hdr;
Packit eace71
	/* Sum now contains sum of IPv6 pseudo header.  Let's add the data
Packit eace71
	   streams. */
Packit eace71
	if (protocol_data_len & 1) {
Packit eace71
		/* Length of data is odd */
Packit eace71
		*((u8_t *) ptr + protocol_data_len) = 0;
Packit eace71
		protocol_data_len++;
Packit eace71
	}
Packit eace71
Packit eace71
	for (i = 0; i < protocol_data_len / 2; i++) {
Packit eace71
		sum += HOST_TO_NET16(*ptr);
Packit eace71
		ptr++;
Packit eace71
	}
Packit eace71
Packit eace71
	sum = (sum >> 16) + (sum & 0xffff);
Packit eace71
	sum += (sum >> 16);
Packit eace71
	sum &= 0xffff;
Packit eace71
	checksum = (u16_t) (~sum);
Packit eace71
	checksum = HOST_TO_NET16(checksum);
Packit eace71
Packit eace71
	switch (ipv6->ipv6_nxt_hdr) {
Packit eace71
	case IPPROTO_ICMPV6:
Packit eace71
		/* Insert correct ICMPv6 checksum */
Packit eace71
		((struct icmpv6_hdr *)(protocol_data_ptr))->icmpv6_cksum =
Packit eace71
			checksum;
Packit eace71
		break;
Packit eace71
	case IPPROTO_UDP:
Packit eace71
		/* Insert correct UDP checksum */
Packit eace71
		((struct udp_hdr *)protocol_data_ptr)->chksum = checksum;
Packit eace71
		break;
Packit eace71
	default:
Packit eace71
		break;
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_is_it_our_link_local_address(struct ipv6_context *context,
Packit eace71
				      struct ipv6_addr *ip_addr)
Packit eace71
{
Packit eace71
	u8_t *test_addr = (u8_t *) ip_addr->addr8;
Packit eace71
	u8_t test_remainder;
Packit eace71
Packit eace71
	if (test_addr[0] != context->link_local_addr.addr8[0])
Packit eace71
		return FALSE;
Packit eace71
Packit eace71
	test_remainder = (test_addr[1] & 0xC0) >> 6;
Packit eace71
	if (test_remainder != 2)
Packit eace71
		return FALSE;
Packit eace71
Packit eace71
	return TRUE;
Packit eace71
}
Packit eace71
Packit eace71
static int ipv6_is_it_our_address(struct ipv6_context *context,
Packit eace71
				  struct ipv6_addr *ipv6_addr)
Packit eace71
{
Packit eace71
	struct ipv6_prefix_entry *ipv6_prefix;
Packit eace71
Packit eace71
	for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
Packit eace71
	     ipv6_prefix = ipv6_prefix->next) {
Packit eace71
		if (IPV6_ARE_ADDR_EQUAL(&ipv6_prefix->ip_addr, ipv6_addr))
Packit eace71
			return TRUE;
Packit eace71
	}
Packit eace71
Packit eace71
	return FALSE;
Packit eace71
}
Packit eace71
Packit eace71
struct ipv6_addr *ipv6_our_address(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	return &context->link_local_addr;
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_ip_in_arp_table(struct ipv6_context *context,
Packit eace71
			 struct ipv6_addr *ip_addr,
Packit eace71
			 struct mac_address *mac_addr)
Packit eace71
{
Packit eace71
	struct ipv6_arp_entry *arp_entry;
Packit eace71
	int i;
Packit eace71
Packit eace71
	for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
Packit eace71
		arp_entry = &context->ipv6_arp_table[i];
Packit eace71
Packit eace71
		if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
Packit eace71
			memcpy((char *)mac_addr, &arp_entry->mac_addr,
Packit eace71
			       sizeof(struct mac_address));
Packit eace71
			return 1;
Packit eace71
		}
Packit eace71
	}
Packit eace71
	return 0;
Packit eace71
}
Packit eace71
Packit eace71
struct ipv6_addr *ipv6_find_longest_match(struct ipv6_context *context,
Packit eace71
				   struct ipv6_addr *ip_addr)
Packit eace71
{
Packit eace71
	struct ipv6_prefix_entry *ipv6_prefix;
Packit eace71
	struct ipv6_prefix_entry *best_match = NULL;
Packit eace71
	int longest_len = -1;
Packit eace71
	int len;
Packit eace71
Packit eace71
	for (ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
Packit eace71
	     ipv6_prefix = ipv6_prefix->next) {
Packit eace71
		if (!IPV6_IS_ADDR_LINKLOCAL(&ipv6_prefix->ip_addr)) {
Packit eace71
			len = best_match_bufcmp((u8_t *)&ipv6_prefix->ip_addr,
Packit eace71
						(u8_t *)ip_addr,
Packit eace71
						sizeof(struct ipv6_addr));
Packit eace71
			if (len > longest_len) {
Packit eace71
				best_match = ipv6_prefix;
Packit eace71
				longest_len = len;
Packit eace71
			}
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	if (best_match)
Packit eace71
		return &best_match->ip_addr;
Packit eace71
Packit eace71
	return NULL;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_arp_out(struct ipv6_context *context, int *uip_len)
Packit eace71
{
Packit eace71
	/* Empty routine */
Packit eace71
}
Packit eace71
Packit eace71
Packit eace71
static void ipv6_update_arp_table(struct ipv6_context *context,
Packit eace71
				  struct ipv6_addr *ip_addr,
Packit eace71
				  struct mac_address *mac_addr)
Packit eace71
{
Packit eace71
	struct ipv6_arp_entry *arp_entry;
Packit eace71
	int i;
Packit eace71
	struct ipv6_arp_entry *ipv6_arp_table = context->ipv6_arp_table;
Packit eace71
Packit eace71
	LOG_DEBUG("IPv6: Neighbor update");
Packit eace71
	/*
Packit eace71
	 * Walk through the ARP mapping table and try to find an entry to
Packit eace71
	 * update. If none is found, the IP -> MAC address mapping is
Packit eace71
	 * inserted in the ARP table.
Packit eace71
	 */
Packit eace71
	for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
Packit eace71
		arp_entry = &ipv6_arp_table[i];
Packit eace71
Packit eace71
		/* Only check those entries that are actually in use. */
Packit eace71
		if (arp_entry->ip_addr.addr[0] != 0) {
Packit eace71
			/*
Packit eace71
			 * Check if the source IP address of the incoming
Packit eace71
			 * packet matches the IP address in this ARP table
Packit eace71
			 * entry.
Packit eace71
			 */
Packit eace71
			if (IPV6_ARE_ADDR_EQUAL(&arp_entry->ip_addr, ip_addr)) {
Packit eace71
				/* An old entry found, update this and return */
Packit eace71
				memcpy((char *)&arp_entry->mac_addr,
Packit eace71
				       (char *)mac_addr,
Packit eace71
				       sizeof(struct mac_address));
Packit eace71
				arp_entry->time = context->arptime;
Packit eace71
				return;
Packit eace71
			}
Packit eace71
		}
Packit eace71
	}
Packit eace71
Packit eace71
	/*
Packit eace71
	 * If we get here, no existing ARP table entry was found, so we
Packit eace71
	 * create one.
Packit eace71
	 *
Packit eace71
	 * First, we try to find an unused entry in the ARP table.
Packit eace71
	 */
Packit eace71
	for (i = 0; i < UIP_ARPTAB_SIZE; i++) {
Packit eace71
		arp_entry = &ipv6_arp_table[i];
Packit eace71
Packit eace71
		if (arp_entry->ip_addr.addr[0] == 0)
Packit eace71
			break;
Packit eace71
	}
Packit eace71
Packit eace71
	if (i == UIP_ARPTAB_SIZE)
Packit eace71
		return;
Packit eace71
Packit eace71
	/* Index j is the entry that is least used */
Packit eace71
	arp_entry = &ipv6_arp_table[i];
Packit eace71
	memcpy((char *)&arp_entry->ip_addr, (char *)ip_addr,
Packit eace71
	       sizeof(struct ipv6_addr));
Packit eace71
	memcpy((char *)&arp_entry->mac_addr,
Packit eace71
	       (char *)mac_addr, sizeof(struct mac_address));
Packit eace71
Packit eace71
	arp_entry->time = context->arptime;
Packit eace71
}
Packit eace71
Packit eace71
/* DestIP is intact */
Packit eace71
int ipv6_send_nd_solicited_packet(struct ipv6_context *context,
Packit eace71
				  struct eth_hdr *eth, struct ipv6_hdr *ipv6)
Packit eace71
{
Packit eace71
	struct icmpv6_hdr *icmp;
Packit eace71
	int pkt_len = 0;
Packit eace71
	struct ipv6_addr *longest_match_addr;
Packit eace71
	char addr_str[INET6_ADDRSTRLEN];
Packit eace71
Packit eace71
	ipv6->ipv6_nxt_hdr = IPPROTO_ICMPV6;
Packit eace71
Packit eace71
	/* Depending on the IPv6 address of the target, we'll need to determine
Packit eace71
	   whether we use the assigned IPv6 address/RA or the link local address
Packit eace71
	*/
Packit eace71
	/* Use Link-local as source address */
Packit eace71
	if (ipv6_is_it_our_link_local_address(context, &ipv6->ipv6_dst) ==
Packit eace71
	    TRUE) {
Packit eace71
		LOG_DEBUG("IPv6: NS using link local");
Packit eace71
		memcpy((char *)&ipv6->ipv6_src,
Packit eace71
		       (char *)&context->link_local_addr,
Packit eace71
		       sizeof(struct ipv6_addr));
Packit eace71
	} else {
Packit eace71
		longest_match_addr =
Packit eace71
		    ipv6_find_longest_match(context, &ipv6->ipv6_dst);
Packit eace71
		if (longest_match_addr) {
Packit eace71
			LOG_DEBUG("IPv6: NS using longest match addr");
Packit eace71
			memcpy((char *)&ipv6->ipv6_src,
Packit eace71
			       (char *)longest_match_addr,
Packit eace71
			       sizeof(struct ipv6_addr));
Packit eace71
		} else {
Packit eace71
			LOG_DEBUG("IPv6: NS using link local instead");
Packit eace71
			memcpy((char *)&ipv6->ipv6_src,
Packit eace71
			       (char *)&context->link_local_addr,
Packit eace71
			       sizeof(struct ipv6_addr));
Packit eace71
		}
Packit eace71
	}
Packit eace71
	icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
Packit eace71
Packit eace71
	inet_ntop(AF_INET6, &ipv6->ipv6_src.addr8, addr_str, sizeof(addr_str));
Packit eace71
	LOG_DEBUG("IPv6: NS host IP addr: %s", addr_str);
Packit eace71
	/*
Packit eace71
	 * Destination IP address to be resolved is after the ICMPv6
Packit eace71
	 * header.
Packit eace71
	 */
Packit eace71
	memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
Packit eace71
	       (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	/*
Packit eace71
	 * Destination IP in the IPv6 header contains solicited-node multicast
Packit eace71
	 * address corresponding to the target address.
Packit eace71
	 *
Packit eace71
	 * ff02::01:ffxx:yyzz. Where xyz are least
Packit eace71
	 * significant of 24-bit MAC address.
Packit eace71
	 */
Packit eace71
	memset((char *)&ipv6->ipv6_dst, 0, sizeof(struct ipv6_addr) - 3);
Packit eace71
	ipv6->ipv6_dst.addr8[0] = 0xff;
Packit eace71
	ipv6->ipv6_dst.addr8[1] = 0x02;
Packit eace71
	ipv6->ipv6_dst.addr8[11] = 0x01;
Packit eace71
	ipv6->ipv6_dst.addr8[12] = 0xff;
Packit eace71
	ipv6_mc_init_dest_mac(eth, ipv6);
Packit eace71
	ipv6->ipv6_hop_limit = 255;
Packit eace71
Packit eace71
	icmp->icmpv6_type = ICMPV6_NEIGH_SOL;
Packit eace71
	icmp->icmpv6_code = 0;
Packit eace71
	icmp->icmpv6_data = 0;
Packit eace71
	icmp->icmpv6_cksum = 0;
Packit eace71
	ipv6_icmp_init_link_option(context,
Packit eace71
				   (struct icmpv6_opt_link_addr *)((u8_t *)icmp
Packit eace71
						+ sizeof(struct icmpv6_hdr)
Packit eace71
						+ sizeof(struct ipv6_addr)),
Packit eace71
						IPV6_ICMP_OPTION_SRC_ADDR);
Packit eace71
	ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
Packit eace71
			  sizeof(struct icmpv6_opt_link_addr) +
Packit eace71
			  sizeof(struct ipv6_addr)));
Packit eace71
	/* Total packet size */
Packit eace71
	pkt_len = (u8_t *) icmp - (u8_t *) eth +
Packit eace71
	    sizeof(struct icmpv6_hdr) +
Packit eace71
	    sizeof(struct icmpv6_opt_link_addr) + sizeof(struct ipv6_addr);
Packit eace71
	ipv6_setup_hdrs(context, eth, ipv6, pkt_len);
Packit eace71
	return pkt_len;
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_init_link_option(struct ipv6_context *context,
Packit eace71
				       struct icmpv6_opt_link_addr *link_opt,
Packit eace71
				       u8_t type)
Packit eace71
{
Packit eace71
	link_opt->hdr.type = type;
Packit eace71
	link_opt->hdr.len = sizeof(struct icmpv6_opt_link_addr) / 8;
Packit eace71
	memcpy((char *)&link_opt->link_addr,
Packit eace71
	       (char *)&context->mac_addr, sizeof(struct mac_address));
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_rx(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	uip_icmp_echo_hdr_t *icmp_echo_hdr =
Packit eace71
				(uip_icmp_echo_hdr_t *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
Packit eace71
	switch (icmp->icmpv6_type) {
Packit eace71
	case ICMPV6_RTR_ADV:
Packit eace71
		ipv6_icmp_handle_router_adv(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	case ICMPV6_NEIGH_SOL:
Packit eace71
		ipv6_icmp_handle_nd_sol(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	case ICMPV6_NEIGH_ADV:
Packit eace71
		ipv6_icmp_handle_nd_adv(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	case ICMPV6_ECHO_REQUEST:
Packit eace71
		/* Response with ICMP reply */
Packit eace71
		ipv6_icmp_handle_echo_request(context);
Packit eace71
		break;
Packit eace71
Packit eace71
	case ICMPV6_ECHO_REPLY:
Packit eace71
		/* Handle ICMP reply */
Packit eace71
		process_icmp_packet(icmp_echo_hdr, context->ustack);
Packit eace71
		break;
Packit eace71
Packit eace71
	default:
Packit eace71
		break;
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_handle_router_adv(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_router_advert *icmp =
Packit eace71
	(struct icmpv6_router_advert *)((u8_t *)ipv6 + sizeof(struct ipv6_hdr));
Packit eace71
	struct icmpv6_opt_hdr *icmp_opt;
Packit eace71
	u16_t opt_len;
Packit eace71
	u16_t len;
Packit eace71
	char addr_str[INET6_ADDRSTRLEN];
Packit eace71
Packit eace71
	if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)
Packit eace71
		return;
Packit eace71
Packit eace71
	opt_len = HOST_TO_NET16(ipv6->ipv6_plen) -
Packit eace71
		  sizeof(struct icmpv6_router_advert);
Packit eace71
Packit eace71
	icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
Packit eace71
				      sizeof(struct icmpv6_router_advert));
Packit eace71
	len = 0;
Packit eace71
	while (len < opt_len) {
Packit eace71
		icmp_opt = (struct icmpv6_opt_hdr *)((u8_t *)icmp +
Packit eace71
					sizeof(struct icmpv6_router_advert) +
Packit eace71
					len);
Packit eace71
Packit eace71
		switch (icmp_opt->type) {
Packit eace71
		case IPV6_ICMP_OPTION_PREFIX:
Packit eace71
			ipv6_icmp_process_prefix(context,
Packit eace71
					(struct icmpv6_opt_prefix *)icmp_opt);
Packit eace71
			context->flags |= IPV6_FLAGS_ROUTER_ADV_RECEIVED;
Packit eace71
			break;
Packit eace71
Packit eace71
		default:
Packit eace71
			break;
Packit eace71
		}
Packit eace71
Packit eace71
		len += icmp_opt->len * 8;
Packit eace71
	}
Packit eace71
Packit eace71
	if (context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED) {
Packit eace71
		LOG_DEBUG("IPv6: RTR ADV nd_ra_flags = 0x%x",
Packit eace71
			  icmp->nd_ra_flags_reserved);
Packit eace71
		if (icmp->nd_ra_curhoplimit > 0)
Packit eace71
			context->hop_limit = icmp->nd_ra_curhoplimit;
Packit eace71
Packit eace71
		if (icmp->nd_ra_flags_reserved & IPV6_RA_MANAGED_FLAG)
Packit eace71
			context->flags |= IPV6_FLAGS_MANAGED_ADDR_CONFIG;
Packit eace71
Packit eace71
		if (icmp->nd_ra_flags_reserved & IPV6_RA_CONFIG_FLAG)
Packit eace71
			context->flags |= IPV6_FLAGS_OTHER_STATEFUL_CONFIG;
Packit eace71
Packit eace71
		if (icmp->nd_ra_router_lifetime != 0) {
Packit eace71
			/* There is a default router. */
Packit eace71
			if (context->ustack->router_autocfg !=
Packit eace71
			    IPV6_RTR_AUTOCFG_OFF)
Packit eace71
				memcpy(
Packit eace71
				   (char *)&context->default_router,
Packit eace71
				       (char *)&ipv6->ipv6_src,
Packit eace71
				       sizeof(struct ipv6_addr));
Packit eace71
			inet_ntop(AF_INET6, &context->default_router,
Packit eace71
				  addr_str, sizeof(addr_str));
Packit eace71
			LOG_DEBUG("IPv6: Got default router IP addr: %s",
Packit eace71
				  addr_str);
Packit eace71
		}
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_process_prefix(struct ipv6_context *context,
Packit eace71
				     struct icmpv6_opt_prefix *icmp_prefix)
Packit eace71
{
Packit eace71
	struct ipv6_addr addr;
Packit eace71
	char addr_str[INET6_ADDRSTRLEN];
Packit eace71
Packit eace71
	/* we only process on-link address info */
Packit eace71
	if (!(icmp_prefix->flags & ICMPV6_OPT_PREFIX_FLAG_ON_LINK))
Packit eace71
		return;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * We only process prefix length of 64 since our Identifier is 64-bit
Packit eace71
	 */
Packit eace71
	if (icmp_prefix->prefix_len == 64) {
Packit eace71
		/* Copy 64-bit from the local-link address to create
Packit eace71
		   IPv6 address */
Packit eace71
		memcpy((char *)&addr,
Packit eace71
		       (char *)&icmp_prefix->prefix, 8);
Packit eace71
		memcpy((char *)&addr.addr8[8],
Packit eace71
		       &context->link_local_addr.addr8[8], 8);
Packit eace71
		inet_ntop(AF_INET6, &addr, addr_str, sizeof(addr_str));
Packit eace71
		LOG_DEBUG("IPv6: Got RA ICMP option IP addr: %s", addr_str);
Packit eace71
		ipv6_add_prefix_entry(context, &addr, 64);
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_handle_nd_adv(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	struct icmpv6_opt_link_addr *link_opt =
Packit eace71
			(struct icmpv6_opt_link_addr *)((u8_t *)icmp +
Packit eace71
			sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
Packit eace71
	struct ipv6_addr *tar_addr6;
Packit eace71
	char addr_str[INET6_ADDRSTRLEN];
Packit eace71
Packit eace71
	/* Added the multicast check for ARP table update */
Packit eace71
	/* Should we qualify for only our host's multicast and our
Packit eace71
	   link_local_multicast?? */
Packit eace71
	LOG_DEBUG("IPv6: Handle nd adv");
Packit eace71
	if ((ipv6_is_it_our_address(context, &ipv6->ipv6_dst) == TRUE) ||
Packit eace71
	    (memcmp((char *)&context->link_local_multi,
Packit eace71
		    (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0) ||
Packit eace71
	    (memcmp((char *)&context->multi,
Packit eace71
		    (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr)) == 0)) {
Packit eace71
		/*
Packit eace71
		 * This is an ARP reply for our addresses. Let's update the
Packit eace71
		 * ARP table.
Packit eace71
		 */
Packit eace71
		ipv6_update_arp_table(context, &ipv6->ipv6_src,
Packit eace71
				      &eth->src_mac);
Packit eace71
Packit eace71
		/* Now check for the target address option and update that as
Packit eace71
		   well */
Packit eace71
		if (link_opt->hdr.type == IPV6_ICMP_OPTION_TAR_ADDR) {
Packit eace71
			tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
Packit eace71
				    sizeof(struct icmpv6_hdr));
Packit eace71
			LOG_DEBUG("IPV6: Target MAC "
Packit eace71
				  "%02x:%02x:%02x:%02x:%02x:%02x",
Packit eace71
				link_opt->link_addr[0], link_opt->link_addr[1],
Packit eace71
				link_opt->link_addr[2], link_opt->link_addr[3],
Packit eace71
				link_opt->link_addr[4], link_opt->link_addr[5]);
Packit eace71
			inet_ntop(AF_INET6, &tar_addr6->addr8, addr_str,
Packit eace71
				  sizeof(addr_str));
Packit eace71
			LOG_DEBUG("IPv6: Target IP addr %s", addr_str);
Packit eace71
			ipv6_update_arp_table(context, tar_addr6,
Packit eace71
			      (struct mac_address *)link_opt->link_addr);
Packit eace71
		}
Packit eace71
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_handle_nd_sol(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	struct icmpv6_opt_link_addr *link_opt =
Packit eace71
			(struct icmpv6_opt_link_addr *)((u8_t *)icmp +
Packit eace71
			sizeof(struct icmpv6_hdr) + sizeof(struct ipv6_addr));
Packit eace71
	int icmpv6_opt_len = 0;
Packit eace71
	struct ipv6_addr tmp;
Packit eace71
	struct ipv6_addr *longest_match_addr, *tar_addr6;
Packit eace71
Packit eace71
	LOG_DEBUG("IPv6: Handle nd sol");
Packit eace71
Packit eace71
	if ((memcmp((char *)&context->mac_addr,
Packit eace71
		    (char *)&eth->dest_mac, sizeof(struct mac_address)) != 0) &&
Packit eace71
	    (iscsiL2IsOurMcAddr(context, (struct mac_address *)&eth->dest_mac)
Packit eace71
	     == FALSE)) {
Packit eace71
		/* This packet is not for us to handle */
Packit eace71
		LOG_DEBUG("IPv6: MAC not addressed to us "
Packit eace71
			  "%02x:%02x:%02x:%02x:%02x:%02x",
Packit eace71
			  eth->dest_mac.addr[0], eth->dest_mac.addr[1],
Packit eace71
			  eth->dest_mac.addr[2], eth->dest_mac.addr[3],
Packit eace71
			  eth->dest_mac.addr[4], eth->dest_mac.addr[5]);
Packit eace71
		return;
Packit eace71
	}
Packit eace71
Packit eace71
	/* Also check for the icmpv6_data before generating the reply */
Packit eace71
	if (ipv6_is_it_our_address(context,
Packit eace71
				   (struct ipv6_addr *) ((u8_t *) icmp +
Packit eace71
						  sizeof(struct icmpv6_hdr)))
Packit eace71
	    == FALSE) {
Packit eace71
		/* This packet is not for us to handle */
Packit eace71
		LOG_DEBUG("IPv6: IP not addressed to us");
Packit eace71
		return;
Packit eace71
	}
Packit eace71
Packit eace71
	/* Copy source MAC to Destination MAC */
Packit eace71
	memcpy((char *)&eth->dest_mac,
Packit eace71
	       (char *)&eth->src_mac, sizeof(struct mac_address));
Packit eace71
Packit eace71
	/* Dest IP contains source IP */
Packit eace71
	memcpy((char *)&tmp,
Packit eace71
	       (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
Packit eace71
	memcpy((char *)&ipv6->ipv6_dst,
Packit eace71
	       (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	/* Examine the Neighbor Solicitation ICMPv6 target address field.
Packit eace71
	   If target address exist, use that to find best match src address
Packit eace71
	   for the reply */
Packit eace71
	if (link_opt->hdr.type == IPV6_ICMP_OPTION_SRC_ADDR) {
Packit eace71
		tar_addr6 = (struct ipv6_addr *)((u8_t *)icmp +
Packit eace71
						 sizeof(struct icmpv6_hdr));
Packit eace71
		if (ipv6_is_it_our_link_local_address(context, tar_addr6)
Packit eace71
		    == TRUE) {
Packit eace71
			LOG_DEBUG("IPv6: NA using link local");
Packit eace71
			memcpy((char *)&ipv6->ipv6_src,
Packit eace71
			       (char *)&context->link_local_addr,
Packit eace71
			       sizeof(struct ipv6_addr));
Packit eace71
		} else {
Packit eace71
			longest_match_addr =
Packit eace71
			      ipv6_find_longest_match(context, tar_addr6);
Packit eace71
			if (longest_match_addr) {
Packit eace71
				LOG_DEBUG("IPv6: NA using longest match addr");
Packit eace71
				memcpy((char *)&ipv6->ipv6_src,
Packit eace71
				       (char *)longest_match_addr,
Packit eace71
				       sizeof(struct ipv6_addr));
Packit eace71
			} else {
Packit eace71
				LOG_DEBUG("IPv6: NA using link local instead");
Packit eace71
				memcpy((char *)&ipv6->ipv6_src,
Packit eace71
				(char *)&context->link_local_addr,
Packit eace71
				       sizeof(struct ipv6_addr));
Packit eace71
			}
Packit eace71
		}
Packit eace71
	} else {
Packit eace71
		/* No target link address, just use whatever it sent to us */
Packit eace71
		LOG_DEBUG("IPv6: NA use dst addr");
Packit eace71
		memcpy((char *)&ipv6->ipv6_src,
Packit eace71
		       (char *)&tmp,
Packit eace71
		       sizeof(struct ipv6_addr));
Packit eace71
	}
Packit eace71
	ipv6->ipv6_hop_limit = 255;
Packit eace71
	icmp->icmpv6_type = ICMPV6_NEIGH_ADV;
Packit eace71
	icmp->icmpv6_code = 0;
Packit eace71
	icmp->icmpv6_data = 0;
Packit eace71
	icmp->icmpv6_cksum = 0;
Packit eace71
	icmp->data.icmpv6_un_data8[0] =
Packit eace71
	    IPV6_NA_FLAG_SOLICITED | IPV6_NA_FLAG_OVERRIDE;
Packit eace71
	memcpy((char *)((u8_t *)icmp + sizeof(struct icmpv6_hdr)),
Packit eace71
	       (char *)&ipv6->ipv6_src,
Packit eace71
	       sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	/* Add the target link address option only for all solicitation */
Packit eace71
	ipv6_icmp_init_link_option(context,
Packit eace71
			(struct icmpv6_opt_link_addr *)((u8_t *)icmp +
Packit eace71
					sizeof(struct icmpv6_hdr) +
Packit eace71
					sizeof(struct ipv6_addr)),
Packit eace71
			IPV6_ICMP_OPTION_TAR_ADDR);
Packit eace71
	icmpv6_opt_len = sizeof(struct icmpv6_opt_link_addr);
Packit eace71
	ipv6->ipv6_plen = HOST_TO_NET16((sizeof(struct icmpv6_hdr) +
Packit eace71
				 icmpv6_opt_len + sizeof(struct ipv6_addr)));
Packit eace71
	LOG_DEBUG("IPv6: Send nd adv");
Packit eace71
	ipv6_send(context,
Packit eace71
		  (u8_t *) icmp - (u8_t *) eth +
Packit eace71
		  sizeof(struct icmpv6_hdr) +
Packit eace71
		  sizeof(struct icmpv6_opt_link_addr) +
Packit eace71
		  sizeof(struct ipv6_addr));
Packit eace71
	return;
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_icmp_handle_echo_request(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct icmpv6_hdr *icmp = (struct icmpv6_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	struct ipv6_addr temp;
Packit eace71
Packit eace71
	/* Copy source MAC to Destination MAC */
Packit eace71
	memcpy((char *)&eth->dest_mac,
Packit eace71
	       (char *)&eth->src_mac, sizeof(struct mac_address));
Packit eace71
Packit eace71
	memcpy((char *)&temp,
Packit eace71
	       (char *)&ipv6->ipv6_dst, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	/* Dest IP contains source IP */
Packit eace71
	memcpy((char *)&ipv6->ipv6_dst,
Packit eace71
	       (char *)&ipv6->ipv6_src, sizeof(struct ipv6_addr));
Packit eace71
	/* Use Link-local as source address */
Packit eace71
	memcpy((char *)&ipv6->ipv6_src,
Packit eace71
	       (char *)&temp, sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	ipv6->ipv6_hop_limit = context->hop_limit;
Packit eace71
	icmp->icmpv6_type = ICMPV6_ECHO_REPLY;
Packit eace71
	icmp->icmpv6_code = 0;
Packit eace71
	icmp->icmpv6_cksum = 0;
Packit eace71
	LOG_DEBUG("IPv6: Send echo reply");
Packit eace71
	ipv6_send(context, (u8_t *) icmp - (u8_t *) eth +
Packit eace71
		  sizeof(struct ipv6_hdr) + HOST_TO_NET16(ipv6->ipv6_plen));
Packit eace71
	return;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_set_ip_params(struct ipv6_context *context,
Packit eace71
			struct ipv6_addr *src_ip, u8_t prefix_len,
Packit eace71
			struct ipv6_addr *default_gateway,
Packit eace71
			struct ipv6_addr *linklocal)
Packit eace71
{
Packit eace71
	if (!(IPV6_IS_ADDR_UNSPECIFIED(src_ip))) {
Packit eace71
		ipv6_add_prefix_entry(context, src_ip, prefix_len);
Packit eace71
		/* Create the multi_dest address */
Packit eace71
		memset(&context->multi_dest, 0, sizeof(struct ipv6_addr));
Packit eace71
		context->multi_dest.addr8[0] = 0xff;
Packit eace71
		context->multi_dest.addr8[1] = 0x02;
Packit eace71
		context->multi_dest.addr8[11] = 0x01;
Packit eace71
		context->multi_dest.addr8[12] = 0xff;
Packit eace71
		context->multi_dest.addr8[13] = src_ip->addr8[13];
Packit eace71
		context->multi_dest.addr16[7] = src_ip->addr16[7];
Packit eace71
		/* Create the multi address */
Packit eace71
		memset(&context->multi, 0, sizeof(struct ipv6_addr));
Packit eace71
		context->multi.addr8[0] = 0xfc;
Packit eace71
		context->multi.addr8[2] = 0x02;
Packit eace71
		context->multi.addr16[7] = src_ip->addr16[7];
Packit eace71
	}
Packit eace71
Packit eace71
	if (!(IPV6_IS_ADDR_UNSPECIFIED(default_gateway))) {
Packit eace71
		/* Override the default gateway addr */
Packit eace71
		memcpy((char *)&context->default_router,
Packit eace71
		       (char *)default_gateway, sizeof(struct ipv6_addr));
Packit eace71
		ipv6_add_prefix_entry(context, default_gateway,
Packit eace71
				      prefix_len);
Packit eace71
	}
Packit eace71
	if (!(IPV6_IS_ADDR_UNSPECIFIED(linklocal))) {
Packit eace71
		/* Override the linklocal addr */
Packit eace71
		memcpy((char *)&context->link_local_addr,
Packit eace71
		       (char *)linklocal, sizeof(struct ipv6_addr));
Packit eace71
		context->link_local_multi.addr8[0] = 0xff;
Packit eace71
		context->link_local_multi.addr8[1] = 0x02;
Packit eace71
		context->link_local_multi.addr8[11] = 0x01;
Packit eace71
		context->link_local_multi.addr8[12] = 0xff;
Packit eace71
		context->link_local_multi.addr8[13] |=
Packit eace71
		    context->link_local_addr.addr8[13];
Packit eace71
		context->link_local_multi.addr16[7] =
Packit eace71
		    context->link_local_addr.addr16[7];
Packit eace71
Packit eace71
		/* Default Prefix length is 64 */
Packit eace71
		/* Add Link local address to the head of the ipv6 address
Packit eace71
		   list */
Packit eace71
		ipv6_add_prefix_entry(context,
Packit eace71
				      &context->link_local_addr, 64);
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_get_source_ip_addrs(struct ipv6_context *context,
Packit eace71
			     struct ipv6_addr_entry *addr_list)
Packit eace71
{
Packit eace71
	struct ipv6_prefix_entry *ipv6_prefix;
Packit eace71
	int i;
Packit eace71
Packit eace71
	for (i = 0, ipv6_prefix = context->addr_list; ipv6_prefix != NULL;
Packit eace71
	     ipv6_prefix = ipv6_prefix->next) {
Packit eace71
		memcpy((char *)&addr_list->ip_addr,
Packit eace71
		       (char *)&ipv6_prefix->ip_addr,
Packit eace71
		       sizeof(struct ipv6_addr));
Packit eace71
		addr_list->prefix_len = ipv6_prefix->prefix_len * 8;
Packit eace71
Packit eace71
		i++;
Packit eace71
		addr_list++;
Packit eace71
	}
Packit eace71
Packit eace71
	return i;
Packit eace71
}
Packit eace71
Packit eace71
int ipv6_get_default_router_ip_addrs(struct ipv6_context *context,
Packit eace71
				     struct ipv6_addr *ip_addr)
Packit eace71
{
Packit eace71
	/* This is a default router. */
Packit eace71
	memcpy((char *)ip_addr,
Packit eace71
	       (char *)&context->default_router,
Packit eace71
	       sizeof(struct ipv6_addr));
Packit eace71
Packit eace71
	return 1;
Packit eace71
}
Packit eace71
Packit eace71
static void ipv6_udp_rx(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	struct eth_hdr *eth =
Packit eace71
			(struct eth_hdr *)context->ustack->data_link_layer;
Packit eace71
	struct ipv6_hdr *ipv6 =
Packit eace71
			(struct ipv6_hdr *)context->ustack->network_layer;
Packit eace71
	struct udp_hdr *udp = (struct udp_hdr *)((u8_t *)ipv6 +
Packit eace71
						sizeof(struct ipv6_hdr));
Packit eace71
	struct dhcpv6_context *dhcpv6c;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * We only care about DHCPv6 packets from the DHCPv6 server.  We drop
Packit eace71
	 * all others.
Packit eace71
	 */
Packit eace71
	if (!(context->flags & IPV6_FLAGS_DISABLE_DHCPV6)) {
Packit eace71
		if ((udp->src_port == HOST_TO_NET16(DHCPV6_SERVER_PORT)) &&
Packit eace71
		    (udp->dest_port == HOST_TO_NET16(DHCPV6_CLIENT_PORT))) {
Packit eace71
			dhcpv6c = context->dhcpv6_context;
Packit eace71
			dhcpv6c->eth = eth;
Packit eace71
			dhcpv6c->ipv6 = ipv6;
Packit eace71
			dhcpv6c->udp = udp;
Packit eace71
			ipv6_udp_handle_dhcp(dhcpv6c);
Packit eace71
		}
Packit eace71
	}
Packit eace71
}
Packit eace71
Packit eace71
struct mac_address *ipv6_get_link_addr(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	return &context->mac_addr;
Packit eace71
}
Packit eace71
Packit eace71
u16_t ipv6_do_stateful_dhcpv6(struct ipv6_context *context, u32_t flags)
Packit eace71
{
Packit eace71
	u16_t task = 0;
Packit eace71
	u16_t ra_flags;
Packit eace71
Packit eace71
	ra_flags = context->flags &
Packit eace71
	    (IPV6_FLAGS_MANAGED_ADDR_CONFIG | IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
Packit eace71
Packit eace71
	if (!(context->flags & IPV6_FLAGS_ROUTER_ADV_RECEIVED)) {
Packit eace71
		LOG_DEBUG("IPv6: There is no IPv6 router on the network");
Packit eace71
		ra_flags |=
Packit eace71
		    (IPV6_FLAGS_MANAGED_ADDR_CONFIG |
Packit eace71
		     IPV6_FLAGS_OTHER_STATEFUL_CONFIG);
Packit eace71
	}
Packit eace71
Packit eace71
	if ((flags & ISCSI_FLAGS_DHCP_TCPIP_CONFIG) &&
Packit eace71
	    (ra_flags & IPV6_FLAGS_MANAGED_ADDR_CONFIG))
Packit eace71
		task |= DHCPV6_TASK_GET_IP_ADDRESS;
Packit eace71
Packit eace71
	if ((flags & ISCSI_FLAGS_DHCP_ISCSI_CONFIG) &&
Packit eace71
	    (ra_flags & IPV6_FLAGS_OTHER_STATEFUL_CONFIG))
Packit eace71
		task |= DHCPV6_TASK_GET_OTHER_PARAMS;
Packit eace71
Packit eace71
	LOG_DEBUG("IPv6: Stateful flags = 0x%x, ra_flags = 0x%x, task = 0x%x",
Packit eace71
		  flags, ra_flags, task);
Packit eace71
Packit eace71
	return task;
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_add_solit_node_address(struct ipv6_context *context,
Packit eace71
				 struct ipv6_addr *ip_addr)
Packit eace71
{
Packit eace71
	struct mac_address mac_addr;
Packit eace71
Packit eace71
	/*
Packit eace71
	 * Add Solicited Node Multicast Address for statically configured IPv6
Packit eace71
	 * address.
Packit eace71
	 */
Packit eace71
	mac_addr.addr[0] = 0x33;
Packit eace71
	mac_addr.addr[1] = 0x33;
Packit eace71
	mac_addr.addr[2] = 0xff;
Packit eace71
	mac_addr.addr[3] = ip_addr->addr8[13];
Packit eace71
	mac_addr.addr[4] = ip_addr->addr8[14];
Packit eace71
	mac_addr.addr[5] = ip_addr->addr8[15];
Packit eace71
	iscsiL2AddMcAddr(context, (struct mac_address *)&mac_addr);
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_cfg_link_local_addr(struct ipv6_context *context,
Packit eace71
			      struct ipv6_addr *ip_addr)
Packit eace71
{
Packit eace71
	memcpy((char *)&context->link_local_addr,
Packit eace71
	       (char *)ip_addr, sizeof(struct ipv6_addr));
Packit eace71
}
Packit eace71
Packit eace71
void ipv6_disable_dhcpv6(struct ipv6_context *context)
Packit eace71
{
Packit eace71
	context->flags |= IPV6_FLAGS_DISABLE_DHCPV6;
Packit eace71
}