From b7b1826930c7da10416bceebce5d63dc8e4086ca Mon Sep 17 00:00:00 2001

From: Sakari Kapanen <sakari.kapanen@optofidelity.com>
Date: Sun, 24 Sep 2017 13:19:25 +0300
Subject: [PATCH] ICMPv6: fix router advertisement

Fixes several errors preventing icmpv6_radvertise.c from being compiled. Fixes conversions to network byte order (namely vlifetime, plifetime, mtu).

IPv6 source address is set to link-local IP address instead of the address in the netdev structure. This is in compliance to RFC 4861. RA didn't work on Linux before this change.

Finally, router prefix and prefix length are derived from the IPv6 address and netmask in the netdev structure. This seems to make more sense than using a predefined, separate prefix from the config.
This commit is contained in:
Sakari Kapanen 2017-09-24 06:33:05 -06:00 committed by Gregory Nutt
parent 3bc21a3973
commit d0f72617ef
2 changed files with 65 additions and 34 deletions

View File

@ -240,8 +240,8 @@ struct icmpv6_router_advertise_s
uint8_t hoplimit; /* Current hop limit */
uint8_t flags; /* See ICMPv6_RADV_FLAG_* definitions */
uint16_t lifetime; /* Router lifetime */
uint16_t reachable[2]; /* Reachable time */
uint16_t retrans[2]; /* Retransmission timer */
uint32_t reachable; /* Reachable time */
uint32_t retrans; /* Retransmission timer */
/* Options begin here */
};
@ -311,8 +311,8 @@ struct icmpv6_prefixinfo_s
uint8_t optlen; /* " " ": Option length: 4 octets */
uint8_t preflen; /* " " ": Prefix length */
uint8_t flags; /* " " ": Flags */
uint16_t vlifetime[2]; /* " " ": Valid lifetime */
uint16_t plifetime[2]; /* Octet 2: Preferred lifetime */
uint32_t vlifetime; /* " " ": Valid lifetime */
uint32_t plifetime; /* Octet 2: Preferred lifetime */
uint16_t reserved[2]; /* " " ": Reserved */
uint16_t prefix[8]; /* Octets 3-4: Prefix */
};
@ -330,7 +330,7 @@ struct icmpv6_mtu_s
uint8_t opttype; /* Octet 1: Option Type: ICMPv6_OPT_MTU */
uint8_t optlen; /* " " ": Option length: 1 octet */
uint16_t reserved; /* " " ": Reserved */
uint16_t mtu[2]; /* " " ": MTU */
uint32_t mtu; /* " " ": MTU */
};
/* The structure holding the ICMP statistics that are gathered if

View File

@ -2,7 +2,7 @@
* net/icmpv6/icmpv6_radvertise.c
* Send an ICMPv6 Router Advertisement
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Adapted for NuttX from logic in uIP which also has a BSD-like license:
@ -86,6 +86,37 @@ static const net_ipv6addr_t g_ipv6_prefix =
HTONS(CONFIG_NET_ICMPv6_PREFIX_8)
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ipv6addr_mask
*
* Description:
* Copy an IPv6 address under a mask
*
* Input Parameters:
* dest - Location to return the masked address
* src - The IPv6 address to mask
* maksk - The address mask
*
* Returned Value:
* None
*
****************************************************************************/
static inline void ipv6addr_mask(FAR uint16_t *dest, FAR const uint16_t *src,
FAR const uint16_t *mask)
{
int i;
for (i = 0; i < 8; ++i)
{
dest[i] = src[i] & mask[i];
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -96,11 +127,11 @@ static const net_ipv6addr_t g_ipv6_prefix =
* Description:
* Send an ICMPv6 Router Advertisement
*
* Parameters:
* Input Parameters:
* dev - The device driver structure containing the outgoing ICMPv6 packet
* buffer
*
* Return:
* Returned Value:
* None
*
* Assumptions:
@ -127,10 +158,10 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
/* Length excludes the IPv6 header */
lladdrsize = netdev_dev_lladdrsize(dev);
l3size = sizeof(icmpv6_router_advertise_s) +
l3size = sizeof(struct icmpv6_router_advertise_s) +
SIZEOF_ICMPV6_SRCLLADDR_S(lladdrsize) +
sizeof(struct icmpv6_mtu_s) +
sizeof(icmpv6_prefixinfo_s);
sizeof(struct icmpv6_prefixinfo_s);
ipv6->len[0] = (l3size >> 8);
ipv6->len[1] = (l3size & 0xff);
@ -141,7 +172,12 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
/* Swap source for destination IP address, add our source IP address */
net_ipv6addr_copy(ipv6->destipaddr, g_ipv6_allnodes);
net_ipv6addr_copy(ipv6->srcipaddr, dev->d_ipv6addr);
/* Source IP address must be set to link-local IP */
ipv6->srcipaddr[0] = HTONS(0xfe80);
memset(&ipv6->srcipaddr[1], 0, 4 * sizeof(uint16_t));
memcpy(&ipv6->srcipaddr[5], &dev->d_mac.ether.ether_addr_octet, sizeof(struct ether_addr));
/* Set up the ICMPv6 Router Advertise response */
@ -151,15 +187,13 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
adv->hoplimit = 64; /* Current hop limit */
adv->flags = ICMPv6_RADV_FLAG_M; /* Managed address flag. */
adv->lifetime = HTONS(1800); /* Router lifetime */
adv->reachable[0] = 0; /* Reachable time */
adv->reachable[1] = 0;
adv->retrans[0] = 0; /* Retransmission timer */
adv->retrans[1] = 0;
adv->reachable = 0; /* Reachable time */
adv->retrans = 0; /* Retransmission timer */
/* Set up the source address option */
srcaddr = (FAR struct icmpv6_srclladdr_s *)
((FAR uint8_t *)adv + sizeof(icmpv6_router_advertise_s));
((FAR uint8_t *)adv + sizeof(struct icmpv6_router_advertise_s));
srcaddr->opttype = ICMPv6_OPT_SRCLLADDR;
srcaddr->optlen = ICMPv6_OPT_OCTECTS(lladdrsize);
memcpy(srcaddr->srclladdr, &dev->d_mac, lladdrsize);
@ -168,30 +202,27 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
mtu = (FAR struct icmpv6_mtu_s *)
((FAR uint8_t *)srcaddr + SIZEOF_ICMPV6_SRCLLADDR_S(lladdrsize));
mtu = &adv->mtu;
mtu->opttype = ICMPv6_OPT_MTU;
mtu->optlen = 1;
mtu->reserved = 0;
mtu->mtu[0] = HTONS(CONFIG_NET_ETH_MTU >> 8);
mtu->mtu[1] = HTONS(CONFIG_NET_ETH_MTU & 0xff);
mtu->mtu = HTONL(CONFIG_NET_ETH_MTU);
/* Set up the prefix option */
prefix = (FAR struct icmpv6_prefixinfo_s *)
((FAR uint8_t *)mtu + sizeof(icmpv6_mtu_s));
prefix = &adv->prefix;
prefix->opttype = ICMPv6_OPT_MTU;
prefix->optlen = 4;
prefix->preflen = CONFIG_NET_ICMPv6_PREFLEN;
prefix->flags = ICMPv6_PRFX_FLAG_L | ICMPv6_PRFX_FLAG_A;
prefix = (FAR struct icmpv6_prefixinfo_s *)
((FAR uint8_t *)mtu + sizeof(struct icmpv6_mtu_s));
prefix->opttype = ICMPv6_OPT_PREFIX;
prefix->optlen = 4;
prefix->flags = ICMPv6_PRFX_FLAG_L | ICMPv6_PRFX_FLAG_A;
prefix->vlifetime = HTONL(2592000);
prefix->plifetime = HTONL(604800);
prefix->reserved[0] = 0;
prefix->reserved[1] = 0;
prefix->vlifetime[0] = HTONS(2592000 >> 8);
prefix->vlifetime[1] = HTONS(2592000 & 0xff);
prefix->plifetime[0] = HTONS(604800 >> 8);
prefix->plifetime[1] = HTONS(604800 & 0xff);
prefix->reserved[0] = 0;
prefix->reserved[1] = 0;
net_ipv6addr_copy(prefix->prefix, g_ipv6_prefix);
/* Set the prefix and prefix length based on net driver IP and netmask */
prefix->preflen = net_ipv6_mask2pref(dev->d_ipv6netmask);
ipv6addr_mask(prefix->prefix, dev->d_ipv6addr, dev->d_ipv6netmask);
/* Calculate the checksum over both the ICMP header and payload */
@ -200,7 +231,7 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
/* Set the size to the size of the IPv6 header and the payload size */
dev->d_len = IPv6_HDRLEN + sizeof(struct icmpv6_router_advertise_s);
dev->d_len = IPv6_HDRLEN + l3size;
#ifdef CONFIG_NET_ETHERNET
/* Add the size of the Ethernet header */