Squashed commit of the following:

net/mld: Checksum calculation needs to know the full size of the IPv6 header, including the size of the extension headers.  The payload size in the IPv64 header must include the extension headers (not considered part of the header in this case).  Fixes a few additional errors in size, endian-ness and checksum calculations.  Wireshark now reports the the outgoing Report has a good checksum.

    net/mld/mld_query.c:  Add a cast to assure that the left shift does not overflow.
This commit is contained in:
Gregory Nutt 2018-11-05 08:56:07 -06:00
parent c6156818b0
commit 33ed27ae65
16 changed files with 75 additions and 49 deletions

View File

@ -354,8 +354,8 @@ struct mld_mcast_listen_report_v2_s
*/
#define SIZEOF_MLD_MCAST_LISTEN_REPORT_V2_S(addreclen) \
(sizeof(struct mld_mcast_addrec_v2_s) - \
sizeof(net_ipv6addr_t) + \
(sizeof(struct mld_mcast_listen_report_v2_s) - \
sizeof(struct mld_mcast_addrec_v2_s) + \
(addreclen))
/* Version 1 Multicast Listener Done (RFC 2710) */

View File

@ -518,7 +518,7 @@ int ipv6_input(FAR struct net_driver_s *dev)
case IP_PROTO_ICMP6: /* ICMP6 input */
/* Forward the ICMPv6 packet */
icmpv6_input(dev, (FAR struct icmpv6_hdr_s *)payload);
icmpv6_input(dev, iphdrlen);
#ifdef CONFIG_NET_6LOWPAN
/* All outgoing ICMPv6 messages come through one of two mechanisms:

View File

@ -155,10 +155,11 @@ struct pollfd; /* Forward reference */
* Handle incoming ICMPv6 input
*
* Input Parameters:
* dev - The device driver structure containing the received ICMPv6
* packet
* icmpv6 - Start of the ICMPv6 payload which may lie at an offset from
* the IPv6 header if IPv6 extension headers are present.
* dev - The device driver structure containing the received ICMPv6
* packet
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* None
@ -168,8 +169,7 @@ struct pollfd; /* Forward reference */
*
****************************************************************************/
void icmpv6_input(FAR struct net_driver_s *dev,
FAR struct icmpv6_hdr_s *icmpv6);
void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen);
/****************************************************************************
* Name: icmpv6_neighbor

View File

@ -150,7 +150,7 @@ void icmpv6_advertise(FAR struct net_driver_s *dev,
/* Calculate the checksum over both the ICMP header and payload */
adv->chksum = 0;
adv->chksum = ~icmpv6_chksum(dev);
adv->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
/* Set the size to the size of the IPv6 header and the payload size */

View File

@ -2,7 +2,7 @@
* net/icmpv6/icmpv6_input.c
* Handling incoming ICMPv6 input
*
* Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2015, 2017-2018 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:
@ -66,8 +66,10 @@
****************************************************************************/
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
#define ICMPv6BUF ((FAR struct icmpv6_hdr_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)]) + iplen)
#define ICMPv6REPLY ((FAR struct icmpv6_echo_reply_s *)icmpv6)
#define ICMPv6SIZE ((dev)->d_len - IPv6_HDRLEN)
#define ICMPv6SIZE ((dev)->d_len - iplen)
#define ICMPv6SOLICIT ((struct icmpv6_neighbor_solicit_s *)icmpv6)
#define ICMPv6ADVERTISE ((struct icmpv6_neighbor_advertise_s *)icmpv6)
@ -214,10 +216,11 @@ drop:
* Handle incoming ICMPv6 input
*
* Input Parameters:
* dev - The device driver structure containing the received ICMPv6
* packet
* icmpv6 - Start of the ICMPv6 payload which may lie at an offset from
* the IPv6 header if IPv6 extension headers are present.
* dev - The device driver structure containing the received ICMPv6
* packet
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* None
@ -227,10 +230,10 @@ drop:
*
****************************************************************************/
void icmpv6_input(FAR struct net_driver_s *dev,
FAR struct icmpv6_hdr_s *icmpv6)
void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
FAR struct icmpv6_hdr_s *icmpv6 = ICMPv6BUF;
#ifdef CONFIG_NET_STATISTICS
g_netstats.icmpv6.recv++;
@ -420,7 +423,7 @@ void icmpv6_input(FAR struct net_driver_s *dev,
net_ipv6addr_copy(ipv6->srcipaddr, dev->d_ipv6addr);
icmpv6->chksum = 0;
icmpv6->chksum = ~icmpv6_chksum(dev);
icmpv6->chksum = ~icmpv6_chksum(dev, iplen);
}
break;

View File

@ -238,7 +238,7 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
/* Calculate the checksum over both the ICMP header and payload */
adv->chksum = 0;
adv->chksum = ~icmpv6_chksum(dev);
adv->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
/* Set the size to the size of the IPv6 header and the payload size */

View File

@ -148,7 +148,7 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev)
/* Calculate the checksum over both the ICMP header and payload */
sol->chksum = 0;
sol->chksum = ~icmpv6_chksum(dev);
sol->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
/* Set the size to the size of the IPv6 header and the payload size */

View File

@ -198,7 +198,7 @@ static void sendto_request(FAR struct net_driver_s *dev,
/* Calculate the ICMPv6 checksum over the ICMPv6 header and payload. */
icmpv6->chksum = 0;
icmpv6->chksum = ~icmpv6_chksum(dev);
icmpv6->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
if (icmpv6->chksum == 0)
{
icmpv6->chksum = 0xffff;

View File

@ -163,7 +163,7 @@ void icmpv6_solicit(FAR struct net_driver_s *dev,
/* Calculate the checksum over both the ICMP header and payload */
sol->chksum = 0;
sol->chksum = ~icmpv6_chksum(dev);
sol->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
/* Set the size to the size of the IPv6 header and the payload size */

View File

@ -311,7 +311,7 @@ int mld_query(FAR struct net_driver_s *dev,
* Query of length 26 octets) MUST be silently ignored.
*/
mldsize = ipv6->len[0] << 8 | ipv6->len[1];
mldsize = (unsigned int)ipv6->len[0] << 8 | ipv6->len[1];
if (mldsize == sizeof(struct mld_mcast_listen_report_v1_s))
{
mldv1 = true;

View File

@ -74,20 +74,24 @@
# define mld_dumppkt(b,n)
#endif
/* IPv6 header size with extensions */
#define RASIZE sizeof(struct ipv6_router_alert_s)
#define MLD_HDRLEN (IPv6_HDRLEN + RASIZE)
/* Buffer layout */
#define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
#define RABUF ((FAR struct ipv6_router_alert_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN))
#define RASIZE sizeof(struct ipv6_router_alert_s)
#define QUERYBUF ((FAR struct mld_mcast_listen_query_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE))
(&dev->d_buf[NET_LL_HDRLEN(dev)] + MLD_HDRLEN))
#define V1REPORTBUF ((FAR struct mld_mcast_listen_report_v1_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE))
(&dev->d_buf[NET_LL_HDRLEN(dev)] + MLD_HDRLEN))
#define V2REPORTBUF ((FAR struct mld_mcast_listen_report_v2_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE))
(&dev->d_buf[NET_LL_HDRLEN(dev)] + MLD_HDRLEN))
#define DONEBUF ((FAR struct mld_mcast_listen_done_v1_s *) \
(&dev->d_buf[NET_LL_HDRLEN(dev)] + IPv6_HDRLEN + RASIZE))
(&dev->d_buf[NET_LL_HDRLEN(dev)] + MLD_HDRLEN))
/****************************************************************************
* Public Functions
@ -174,11 +178,13 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
* header length)
*/
dev->d_len = IPv6_HDRLEN + RASIZE + mldsize;
dev->d_len = MLD_HDRLEN + mldsize;
/* The total size of the data is the size of the ICMPv6 payload */
/* The total size of the data is the size of the ICMPv6 payload PLUS the
* size of the IPv6 extension headers.
*/
dev->d_sndlen = mldsize;
dev->d_sndlen = RASIZE + mldsize;
/* Set up the IPv6 header */
@ -187,7 +193,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
ipv6->tcf = 0; /* Traffic class(LS)/Flow label(MS) */
ipv6->flow = 0; /* Flow label (LS) */
ipv6->len[0] = (dev->d_sndlen >> 8); /* Length excludes the IPv6 header */
ipv6->len[1] = (dev->d_sndlen & 0xff);
ipv6->len[1] = (dev->d_sndlen & 0xff); /* but includes the extension headers */
ipv6->proto = NEXT_HOPBYBOT_EH; /* Hop-to-hop extension header */
ipv6->ttl = MLD_TTL; /* MLD Time-to-live */
@ -281,7 +287,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
/* Calculate the ICMPv6 checksum. */
query->chksum = 0;
query->chksum = ~icmpv6_chksum(dev);
query->chksum = ~icmpv6_chksum(dev, MLD_HDRLEN);
MLD_STATINCR(g_netstats.mld.query_sent);
}
@ -300,7 +306,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
/* Calculate the ICMPv6 checksum. */
report->chksum = 0;
report->chksum = ~icmpv6_chksum(dev);
report->chksum = ~icmpv6_chksum(dev, MLD_HDRLEN);
SET_MLD_LASTREPORT(group->flags); /* Remember we were the last to report */
MLD_STATINCR(g_netstats.mld.report_sent);
@ -316,7 +322,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
memset(report, 0, mldsize);
report->type = ICMPV6_MCAST_LISTEN_REPORT_V2;
report->naddrec = 1;
report->naddrec = HTONS(1);
addrec = report->addrec;
addrec->rectype = MODE_IS_INCLUDE;
@ -325,7 +331,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
/* Calculate the ICMPv6 checksum. */
report->chksum = 0;
report->chksum = ~icmpv6_chksum(dev);
report->chksum = ~icmpv6_chksum(dev, MLD_HDRLEN);
SET_MLD_LASTREPORT(group->flags); /* Remember we were the last to report */
MLD_STATINCR(g_netstats.mld.report_sent);
@ -345,7 +351,7 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
/* Calculate the ICMPv6 checksum. */
done->chksum = 0;
done->chksum = ~icmpv6_chksum(dev);
done->chksum = ~icmpv6_chksum(dev, MLD_HDRLEN);
MLD_STATINCR(g_netstats.mld.done_sent);
}

View File

@ -85,9 +85,9 @@ uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len)
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6
uint16_t icmpv6_chksum(FAR struct net_driver_s *dev)
uint16_t icmpv6_chksum(FAR struct net_driver_s *dev, unsigned int iplen)
{
return ipv6_upperlayer_chksum(dev, IP_PROTO_ICMP6);
return ipv6_upperlayer_chksum(dev, IP_PROTO_ICMP6, iplen);
}
#endif

View File

@ -1,7 +1,8 @@
/****************************************************************************
* net/utils/net_ipchksum.c
*
* Copyright (C) 2007-2010, 2012, 2014-2015, 2017 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2010, 2012, 2014-2015, 2017-2018 Gregory Nutt. All
* rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -40,6 +41,7 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/netdev.h>
@ -64,7 +66,7 @@
* Name: ipv4_upperlayer_chksum
*
* Description:
* Perform the checksum calcaultion over the IPv4, protocol headers, and
* Perform the checksum calculation over the IPv4, protocol headers, and
* data payload as necessary.
*
* Input Parameters:
@ -125,6 +127,9 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto)
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
@ -132,18 +137,26 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto)
****************************************************************************/
#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv6)
uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto)
uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev,
uint8_t proto, unsigned int iplen)
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
uint16_t upperlen;
uint16_t sum;
DEBUGASSERT(dev != NULL && iplen >= IPv6_HDRLEN);
/* The length reported in the IPv6 header is the length of the payload
* that follows the header.
* that follows the header. If extension heders are present, then this
* size includes the size of the IPv6 extension headers.
*/
upperlen = ((uint16_t)ipv6->len[0] << 8) + ipv6->len[1];
/* Adjust for the presence of any extension headers */
upperlen -= (iplen - IPv6_HDRLEN);
/* Verify some minimal assumptions */
if (upperlen > NETDEV_PKTSIZE(dev))
@ -164,7 +177,7 @@ uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto)
/* Sum IP payload data. */
sum = chksum(sum, &dev->d_buf[IPv6_HDRLEN + NET_LL_HDRLEN(dev)], upperlen);
sum = chksum(sum, &dev->d_buf[NET_LL_HDRLEN(dev) + iplen], upperlen);
return (sum == 0) ? 0xffff : htons(sum);
}
#endif /* CONFIG_NET_ARCH_CHKSUM */

View File

@ -82,7 +82,7 @@ uint16_t tcp_ipv4_chksum(FAR struct net_driver_s *dev)
#ifdef CONFIG_NET_IPv6
uint16_t tcp_ipv6_chksum(FAR struct net_driver_s *dev)
{
return ipv6_upperlayer_chksum(dev, IP_PROTO_TCP);
return ipv6_upperlayer_chksum(dev, IP_PROTO_TCP, IPv6_HDRLEN);
}
#endif /* CONFIG_NET_IPv6 */
#endif /* !CONFIG_NET_ARCH_CHKSUM */

View File

@ -78,7 +78,7 @@ uint16_t udp_ipv4_chksum(FAR struct net_driver_s *dev)
#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv6)
uint16_t udp_ipv6_chksum(FAR struct net_driver_s *dev)
{
return ipv6_upperlayer_chksum(dev, IP_PROTO_UDP);
return ipv6_upperlayer_chksum(dev, IP_PROTO_UDP, IPv6_HDRLEN);
}
#endif

View File

@ -295,6 +295,9 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto);
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
@ -302,7 +305,8 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto);
****************************************************************************/
#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv6)
uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto);
uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev,
uint8_t proto, unsigned int iplen);
#endif
/****************************************************************************
@ -387,7 +391,7 @@ uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len);
****************************************************************************/
#ifdef CONFIG_NET_ICMPv6
uint16_t icmpv6_chksum(FAR struct net_driver_s *dev);
uint16_t icmpv6_chksum(FAR struct net_driver_s *dev, unsigned int iplen);
#endif
#undef EXTERN