Networking: Rethink IPv6 all-nodes packet routing.

This commit is contained in:
Gregory Nutt 2017-08-08 07:48:07 -06:00
parent 680368b656
commit 572cf51fa4
4 changed files with 66 additions and 23 deletions

View File

@ -24,15 +24,15 @@ config SPIRIT_PKTLEN
Fixed pkt sizes are used. This setting describes that fixed packet
size.
"Sometimes Spirit1 seems to NOT deliver (correctly) the 'IRQ_RX_DATA_READY'
event for packets which have a length which is close to a multiple of
RX FIFO size. Furthermore, in these cases also the content delivery seems
to be compromised as well as the generation of RX/TX FIFO errors.
This can be avoided by reducing the maximum packet length to a value which
is lower than the RX FIFO size."
Also, with a packet size of 96, I have seen CRC failures on the receiving
side. With a packet size of 94, CRC filtering behaves well.
This comment exists in the STMicro Spirit driver. I have not
experienced this myself, but this is something you should be aware
of: "Sometimes Spirit1 seems to NOT deliver (correctly) the
'IRQ_RX_DATA_READY' event for packets which have a length which is
close to a multiple of RX FIFO size. Furthermore, in these cases
also the content delivery seems to be compromised as well as the
generation of RX/TX FIFO errors. This can be avoided by reducing
the maximum packet length to a value which is lower than the RX FIFO
size."
config SPIRIT_FIFOS
bool "FIFO Watermarks"
@ -48,12 +48,15 @@ config SPIRIT_FIFOS
occurrences of RX FIFO errors if the packet size is less than but close
to 96.
"Sometimes Spirit1 seems to NOT deliver (correctly) the 'IRQ_RX_DATA_READY'
event for packets which have a length which is close to a multiple of
RX FIFO size. Furthermore, in these cases also the content delivery seems
to be compromised as well as the generation of RX/TX FIFO errors.
This can be avoided by reducing the maximum packet length to a value which
is lower than the RX FIFO size."
This comment exists in the STMicro Spirit driver. I have not
experienced this myself, but this is something you should be aware
of: "Sometimes Spirit1 seems to NOT deliver (correctly) the
'IRQ_RX_DATA_READY' event for packets which have a length which is
close to a multiple of RX FIFO size. Furthermore, in these cases
also the content delivery seems to be compromised as well as the
generation of RX/TX FIFO errors. This can be avoided by reducing
the maximum packet length to a value which is lower than the RX FIFO
size."
From my reading, the only known work-around is to reduce the maximum
packet size so that it is smaller than 96. Hence, this option is
@ -86,6 +89,13 @@ config SPIRIT_CRCDISABLE
---help---
Disables CRC calculation and filtering. Default is enabled.
Errata: "Using the STack packet format and no CRC field, the
reading from RX FIFO to the last received byte, is not possible. ..."
Workaround: "By configuring the packet handler with at least one byte
of CRC, the problem is solved. If the CRC is not required in the
application, configure one byte of CRC in the receiver only, to read
the payload correctly from RX FIFO."
config SPIRIT_HUBNODE
hex "Address of hub node"
default 0x34

View File

@ -92,8 +92,8 @@ EXTERN uint16_t g_ipid;
#ifdef CONFIG_NET_IPv6
EXTERN const net_ipv6addr_t g_ipv6_allzeroaddr; /* An address of all zeroes */
#if defined(CONFIG_NET_ICMPv6_AUTOCONF) || defined(CONFIG_NET_ICMPv6_ROUTER)
EXTERN const net_ipv6addr_t g_ipv6_allnodes; /* All link local nodes */
#if defined(CONFIG_NET_ICMPv6_AUTOCONF) || defined(CONFIG_NET_ICMPv6_ROUTER)
EXTERN const net_ipv6addr_t g_ipv6_allrouters; /* All link local routers */
#ifdef CONFIG_NET_ICMPv6_AUTOCONF
EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link address */

View File

@ -53,10 +53,12 @@
#include <errno.h>
#include <debug.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/sixlowpan.h>
#include <nuttx/wireless/pktradio.h>
#include <nuttx/wireless/ieee802154/ieee802154_mac.h>
#include "inet/inet.h"
#include "sixlowpan/sixlowpan_internal.h"
#ifdef CONFIG_NET_6LOWPAN
@ -233,9 +235,7 @@ int sixlowpan_destaddrfromip(FAR struct sixlowpan_driver_s *radio,
* disturbing every interface in the network.
*/
if (ipaddr[1] == 0 && ipaddr[2] == 0 && ipaddr[3] == 0 &&
ipaddr[4] == 0 && ipaddr[5] == 0 && ipaddr[5] == 0 &&
ipaddr[7] == HTONS(0x0001))
if (net_ipv6addr_cmp(ipaddr, g_ipv6_allnodes))
{
memcpy(destaddr, &properties.sp_bcast,
sizeof(struct netdev_varaddr_s));

View File

@ -277,6 +277,9 @@ static uint16_t udp_select_port(void)
static inline FAR struct udp_conn_s *
udp_ipv4_active(FAR struct net_driver_s *dev, FAR struct udp_hdr_s *udp)
{
#ifdef CONFIG_NET_BROADCAST
static const inaddr_t bcast = INADDR_BROADCAST;
#endif
FAR struct ipv4_hdr_s *ip = IPv4BUF;
FAR struct udp_conn_s *conn;
@ -315,13 +318,26 @@ static inline FAR struct udp_conn_s *
if (conn->lport != 0 && udp->destport == conn->lport &&
(conn->rport == 0 || udp->srcport == conn->rport) &&
#ifdef CONFIG_NETDEV_MULTINIC
/* Local port accepts any address on this port or there
* is an exact match in destipaddr and the bound local
* address. This catches the receipt of a broadcast when
* the socket is bound to INADDR_ANY.
*/
(net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY) ||
net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_BROADCAST) ||
net_ipv4addr_hdrcmp(ip->destipaddr, &conn->u.ipv4.laddr)) &&
#endif
/* If not connected to a remote address, or a broadcast address
* destipaddr was received, or there is an exact match between the
* srcipaddr and the bound IP address, then accept the packet.
*/
(net_ipv4addr_cmp(conn->u.ipv4.raddr, INADDR_ANY) ||
net_ipv4addr_cmp(conn->u.ipv4.raddr, INADDR_BROADCAST) ||
#ifdef CONFIG_NET_BROADCAST
net_ipv4addr_hdrcmp(ip->destipaddr, &bcast) ||
#endif
net_ipv4addr_hdrcmp(ip->srcipaddr, &conn->u.ipv4.raddr)))
{
/* Matching connection found.. return a reference to it */
@ -370,7 +386,7 @@ static inline FAR struct udp_conn_s *
* - If multiple network interfaces are supported, then the local
* IP address is available and we will insist that the
* destination IP matches the bound address. If a socket is bound to
* INADDRY_ANY (laddr), then it should receive all packets directed
* INADDR6_ANY (laddr), then it should receive all packets directed
* to the port. REVISIT: Should also depend on SO_BROADCAST.
* - Finally, if the connection is bound to a remote IP address,
* the source IP address of the packet is checked.
@ -380,7 +396,8 @@ static inline FAR struct udp_conn_s *
*
* To send and receive multicast packets, the application should:
*
* - Bind socket to INADDR6_ANY or to a specific <multicast-address>
* - Bind socket to INADDR6_ANY (for the all-nodes multicast address)
* or to a specific <multicast-address>
* - setsockopt to SO_BROADCAST (for all-nodes address)
* - call sendto with sendaddr.sin_addr.s_addr = <multicast-address>
* - call recvfrom.
@ -390,11 +407,27 @@ static inline FAR struct udp_conn_s *
if (conn->lport != 0 && udp->destport == conn->lport &&
(conn->rport == 0 || udp->srcport == conn->rport) &&
#ifdef CONFIG_NETDEV_MULTINIC
/* Local port accepts any address on this port or there
* is an exact match in destipaddr and the bound local
* address. This catches the cast of the all nodes multicast
* when the socket is bound to INADDR6_ANY.
*/
(net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_allzeroaddr) ||
net_ipv6addr_hdrcmp(ip->destipaddr, conn->u.ipv6.laddr)) &&
#endif
/* If not connected to a remote address, or a all-nodes multicast
* destipaddr was received, or there is an exact match between the
* srcipaddr and the bound remote IP address, then accept the
* packet.
*/
(net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_allzeroaddr) ||
#ifdef CONFIG_NET_BROADCAST
net_ipv6addr_hdrcmp(ip->destipaddr, g_ipv6_allnodes) ||
#endif
net_ipv6addr_hdrcmp(ip->srcipaddr, conn->u.ipv6.raddr)))
{
/* Matching connection found.. return a reference to it */