Networking: Fix issues with UDP packet length and checksum calculations when IPv6 is selected

This commit is contained in:
Gregory Nutt 2015-01-23 09:33:18 -06:00
parent e22848c19c
commit f4ce875711
5 changed files with 105 additions and 46 deletions

View File

@ -99,6 +99,7 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
FAR struct udp_conn_s *conn;
unsigned int udpiplen;
unsigned int hdrlen;
uint16_t chksum;
int ret = OK;
/* Update the count of UDP packets received */
@ -126,13 +127,34 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
* application sets d_sndlen, it has a packet to send.
*/
dev->d_len -= udpiplen;
#ifdef CONFIG_NET_UDP_CHECKSUMS
dev->d_len -= udpiplen;
dev->d_appdata = &dev->d_buf[hdrlen];
if (udp->udpchksum != 0 && udp_chksum(dev) != 0xffff)
#ifdef CONFIG_NET_UDP_CHECKSUMS
chksum = udp->udpchksum;
if (chksum != 0)
{
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
if (IFF_IS_IPv6(dev->d_flags))
#endif
{
chksum = ~udp_ipv6_chksum(dev);
}
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
else
#endif
{
chksum = ~udp_ipv4_chksum(dev);
}
#endif /* CONFIG_NET_IPv6 */
}
if (chksum != 0)
{
#ifdef CONFIG_NET_STATISTICS
g_netstats.udp.drop++;
g_netstats.udp.chkerr++;

View File

@ -129,8 +129,6 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
ipv4->vhl = 0x45;
ipv4->tos = 0;
ipv4->len[0] = (dev->d_len >> 8);
ipv4->len[1] = (dev->d_len & 0xff);
++g_ipid;
ipv4->ipid[0] = g_ipid >> 8;
ipv4->ipid[1] = g_ipid & 0xff;
@ -142,17 +140,22 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr);
net_ipv4addr_hdrcopy(ipv4->destipaddr, &conn->u.ipv4.raddr);
/* Calculate IP checksum. */
ipv4->ipchksum = 0;
ipv4->ipchksum = ~ipv4_chksum(dev);
/* The total length to send is the size of the application data
* plus the IPv4 and UDP headers (and, eventually, the link layer
* header)
*/
dev->d_len = dev->d_sndlen + IPv4UDP_HDRLEN;
dev->d_len = dev->d_sndlen + IPv4UDP_HDRLEN;
/* The IPv4 length includes the size of the IPv4 header */
ipv4->len[0] = (dev->d_len >> 8);
ipv4->len[1] = (dev->d_len & 0xff);
/* Calculate IP checksum. */
ipv4->ipchksum = 0;
ipv4->ipchksum = ~ipv4_chksum(dev);
}
#endif /* CONFIG_NET_IPv4 */
@ -175,20 +178,26 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
ipv6->vtc = 0x60;
ipv6->tcf = 0x00;
ipv6->flow = 0x00;
ipv6->len[0] = (dev->d_sndlen >> 8);
ipv6->len[1] = (dev->d_sndlen & 0xff);
ipv6->proto = IP_PROTO_UDP;
ipv6->ttl = conn->ttl;
net_ipv6addr_copy(ipv6->srcipaddr, dev->d_ipv6addr);
net_ipv6addr_copy(ipv6->destipaddr, conn->u.ipv6.raddr);
/* The IPv6 length, Includes the UDP header size but not the IPv6
* header size
*/
dev->d_len = dev->d_sndlen + UDP_HDRLEN;
ipv6->len[0] = (dev->d_len >> 8);
ipv6->len[1] = (dev->d_len & 0xff);
/* The total length to send is the size of the application data
* plus the IPv4 and UDP headers (and, eventually, the link layer
* plus the IPv6 and UDP headers (and, eventually, the link layer
* header)
*/
dev->d_len = dev->d_sndlen + IPv6UDP_HDRLEN;
dev->d_len += IPv6_HDRLEN;
}
#endif /* CONFIG_NET_IPv6 */
@ -197,19 +206,34 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
udp->srcport = conn->lport;
udp->destport = conn->rport;
udp->udplen = HTONS(dev->d_sndlen + UDP_HDRLEN);
udp->udpchksum = 0;
#ifdef CONFIG_NET_UDP_CHECKSUMS
/* Calculate UDP checksum. */
udp->udpchksum = 0;
udp->udpchksum = ~(udp_chksum(dev));
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv5
if (conn->domain = PF_INET)
#endif
{
udp->udpchksum = ~udp_ipv4_chksum(dev);
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
#endif
{
udp->udpchksum = ~udp_ipv6_chksum(dev);
}
#endif /* CONFIG_NET_IPv6 */
if (udp->udpchksum == 0)
{
udp->udpchksum = 0xffff;
}
#else
udp->udpchksum = 0;
#endif
#endif /* CONFIG_NET_UDP_CHECKSUMS */
nllvdbg("Outgoing UDP packet length: %d\n", dev->d_len);

View File

@ -23,4 +23,5 @@ config NET_ARCH_CHKSUM
uint16_t ipv4_chksum(FAR struct net_driver_s *dev)
uint16_t tcp_ipv4_chksum(FAR struct net_driver_s *dev);
uint16_t tcp_ipv6_chksum(FAR struct net_driver_s *dev);
uint16_t udp_chksum(FAR struct net_driver_s *dev);
uint16_t udp_ipv4_chksum(FAR struct net_driver_s *dev);
uint16_t udp_ipv6_chksum(FAR struct net_driver_s *dev);

View File

@ -372,34 +372,34 @@ uint16_t tcp_chksum(FAR struct net_driver_s *dev)
#endif
/****************************************************************************
* Name: udp_chksum
* Name: udp_ipv4_chksum
*
* Description:
* Calculate the UDP checksum of the packet in d_buf and d_appdata.
* Calculate the UDP/IPv4 checksum of the packet in d_buf and d_appdata.
*
****************************************************************************/
#if defined(CONFIG_NET_UDP_CHECKSUMS) && !defined(CONFIG_NET_ARCH_CHKSUM)
uint16_t udp_chksum(FAR struct net_driver_s *dev)
#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv4)
uint16_t udp_ipv4_chksum(FAR struct net_driver_s *dev)
{
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
if (IFF_IS_IPv6(dev->d_flags))
{
return ipv6_upperlayer_chksum(dev, IP_PROTO_UDP);
}
else
{
return ipv4_upperlayer_chksum(dev, IP_PROTO_UDP);
}
#elif defined(CONFIG_NET_IPv4)
return ipv4_upperlayer_chksum(dev, IP_PROTO_UDP);
#else /* if defined(CONFIG_NET_IPv6) */
return ipv6_upperlayer_chksum(dev, IP_PROTO_UDP);
#endif
}
#endif /* CONFIG_NET_UDP_CHECKSUMS && !CONFIG_NET_ARCH_CHKSUM */
#endif
/****************************************************************************
* Name: udp_ipv6_chksum
*
* Description:
* Calculate the UDP/IPv6 checksum of the packet in d_buf and d_appdata.
*
****************************************************************************/
#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);
}
#endif
/****************************************************************************
* Name: icmp_chksum

View File

@ -176,15 +176,27 @@ uint16_t tcp_chksum(FAR struct net_driver_s *dev);
/****************************************************************************
* Name: udp_chksum
* Name: udp_ipv4_chksum
*
* Description:
* Calculate the UDP checksum of the packet in d_buf and d_appdata.
* Calculate the UDP/IPv4 checksum of the packet in d_buf and d_appdata.
*
****************************************************************************/
#ifdef CONFIG_NET_UDP_CHECKSUMS
uint16_t udp_chksum(FAR struct net_driver_s *dev);
#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv4)
uint16_t udp_ipv4_chksum(FAR struct net_driver_s *dev);
#endif
/****************************************************************************
* Name: udp_ipv6_chksum
*
* Description:
* Calculate the UDP/IPv6 checksum of the packet in d_buf and d_appdata.
*
****************************************************************************/
#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv6)
uint16_t udp_ipv6_chksum(FAR struct net_driver_s *dev);
#endif
/****************************************************************************