|
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 *)ð->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 |
ð->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 *)ð->dest_mac, sizeof(struct mac_address)) != 0) &&
|
|
Packit |
eace71 |
(iscsiL2IsOurMcAddr(context, (struct mac_address *)ð->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 *)ð->dest_mac,
|
|
Packit |
eace71 |
(char *)ð->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 *)ð->dest_mac,
|
|
Packit |
eace71 |
(char *)ð->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 |
}
|