net/netdev: modify for hardware checksum offload

Implementation of main hardware verification and uninstallation functions

Signed-off-by: daichuan <daichuan@xiaomi.com>
This commit is contained in:
daichuan
2025-08-30 01:17:47 +08:00
committed by Xiang Xiao
parent 9903b11656
commit d2dde8a29a
9 changed files with 287 additions and 10 deletions
+9
View File
@@ -80,6 +80,11 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
/* Hardware features bits */
#define NETDEV_TX_CSUM (1 << 1) /* Netdev support hardware tx checksum */
#define NETDEV_RX_CSUM (1 << 2) /* Netdev support hardware rx checksum */
/* Determine the largest possible address */ /* Determine the largest possible address */
#if defined(CONFIG_WIRELESS_IEEE802154) && defined(CONFIG_WIRELESS_PKTRADIO) #if defined(CONFIG_WIRELESS_IEEE802154) && defined(CONFIG_WIRELESS_PKTRADIO)
@@ -341,6 +346,10 @@ struct net_driver_s
uint32_t d_flags; uint32_t d_flags;
/* Hardware features. See NETDEV_* definitions */
uint8_t d_features;
/* Multi network devices using multiple link layer protocols are /* Multi network devices using multiple link layer protocols are
* supported * supported
*/ */
+2 -1
View File
@@ -447,7 +447,8 @@ static int ipv4_in(FAR struct net_driver_s *dev)
#endif #endif
#ifdef CONFIG_NET_IPV4_CHECKSUMS #ifdef CONFIG_NET_IPV4_CHECKSUMS
if (ipv4_chksum(IPv4BUF) != 0xffff) if (((dev->d_features & NETDEV_RX_CSUM) == 0)
&& (ipv4_chksum(IPv4BUF) != 0xffff))
{ {
/* Compute and check the IP header checksum. */ /* Compute and check the IP header checksum. */
+1
View File
@@ -59,6 +59,7 @@ static uint16_t g_ipid;
* src_ip Source IPv4 address * src_ip Source IPv4 address
* dst_ip Destination IPv4 address * dst_ip Destination IPv4 address
* ttl Time to live(IPv4) * ttl Time to live(IPv4)
* tos Type of Service(IPv4)
* opt IPv4 options * opt IPv4 options
* *
* Returned Value: * Returned Value:
+9
View File
@@ -99,4 +99,13 @@ config NETDOWN_NOTIFIER
notifier, but was developed specifically to support SIGHUP poll() notifier, but was developed specifically to support SIGHUP poll()
logic. logic.
config NETDEV_CHECKSUM
bool "netdev hardware checksum"
default n
---help---
To support hardware checksum calculation for network cards, we
need to know the starting position of the L4 layer header in
the iob buffer, as well as the offset of the checksum field
within the L4 layer.
endmenu # Network Device Operations endmenu # Network Device Operations
+195
View File
@@ -0,0 +1,195 @@
/****************************************************************************
* net/netdev/netdev_checksum.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/net/netdev.h>
#include "netdev/netdev.h"
#ifdef CONFIG_NETDEV_CHECKSUM
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: hardware_chksum_start
*
* Description:
* get checksum start offset position with iob buffer
*
* Input Parameters:
* dev - The driver structure
* iphdrlen - ipv4/ipv6 header length
*
* Returned Value:
* The checksum start offset position
*
****************************************************************************/
static int32_t hardware_chksum_start(FAR struct iob_s *iob,
uint16_t iphdrlen)
{
int32_t start = 0;
if (iphdrlen > iob->io_len)
{
return -EINVAL;
}
if (iob != NULL)
{
start = iob->io_offset + iphdrlen;
}
return start;
}
/****************************************************************************
* Name: hardware_chksum_get_proto
*
* Description:
* get proto with dev.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The proto value
*
****************************************************************************/
static uint8_t hardware_chksum_get_proto(FAR struct net_driver_s *dev)
{
uint8_t proto;
if (IFF_IS_IPv6(dev->d_flags))
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
proto = ipv6->proto;
}
else
{
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
proto = ipv4->proto;
}
return proto;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: netdev_checksum_start
*
* Description:
* get checksum start offset position with iob, then hardwear can
* use to calculate the package payload checksum value.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The checksum start offset position, -EINVAL is mean not need calculate
* with hardware
*
****************************************************************************/
int netdev_checksum_start(FAR struct net_driver_s *dev)
{
int start;
if (IFF_IS_IPv6(dev->d_flags))
{
FAR struct ipv6_hdr_s *ipv6 =
(FAR struct ipv6_hdr_s *)(IOB_DATA(dev->d_iob));
if ((ipv6->proto == IP_PROTO_UDP) || (ipv6->proto == IP_PROTO_TCP))
{
start = hardware_chksum_start(dev->d_iob, IPv6_HDRLEN);
}
else
{
return -EINVAL;
}
}
else
{
FAR struct ipv4_hdr_s *ipv4 =
(FAR struct ipv4_hdr_s *)(IOB_DATA(dev->d_iob));
if ((ipv4->proto == IP_PROTO_UDP) || (ipv4->proto == IP_PROTO_TCP))
{
start = hardware_chksum_start(dev->d_iob,
((ipv4->vhl & IPv4_HLMASK) << 2));
}
else
{
return -EINVAL;
}
}
return start;
}
/****************************************************************************
* Name: netdev_checksum_offset
*
* Description:
* get checksum field offset with tcp/udp header.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The checksum field offset with L4, -EINVAL is mean not need calculate
* with hardware
*
****************************************************************************/
int netdev_checksum_offset(FAR struct net_driver_s *dev)
{
int offset = 0;
uint8_t proto = hardware_chksum_get_proto(dev);
if (proto == IP_PROTO_UDP)
{
offset = offsetof(struct udp_hdr_s, udpchksum);
}
else if (proto == IP_PROTO_TCP)
{
offset = offsetof(struct tcp_hdr_s, tcpchksum);
}
else
{
return -EINVAL;
}
return offset;
}
#endif /* CONFIG_NETDEV_CHECKSUM */
+2 -1
View File
@@ -726,7 +726,8 @@ static void tcp_input(FAR struct net_driver_s *dev, uint8_t domain,
#ifdef CONFIG_NET_TCP_CHECKSUMS #ifdef CONFIG_NET_TCP_CHECKSUMS
/* Start of TCP input header processing code. */ /* Start of TCP input header processing code. */
if (tcp_chksum(dev) != 0xffff) if (((dev->d_features & NETDEV_RX_CSUM) == 0)
&& (tcp_chksum(dev) != 0xffff))
{ {
/* Compute and check the TCP checksum. */ /* Compute and check the TCP checksum. */
+42 -4
View File
@@ -200,7 +200,17 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
tcp->tcpchksum = 0; tcp->tcpchksum = 0;
#ifdef CONFIG_NET_TCP_CHECKSUMS #ifdef CONFIG_NET_TCP_CHECKSUMS
tcp->tcpchksum = ~tcp_ipv6_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
tcp->tcpchksum = ~tcp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_TCP,
IPv6_HDRLEN);
tcp->tcpchksum = HTONS(chksum);
}
#endif #endif
#ifdef CONFIG_NET_STATISTICS #ifdef CONFIG_NET_STATISTICS
@@ -224,7 +234,16 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
tcp->tcpchksum = 0; tcp->tcpchksum = 0;
#ifdef CONFIG_NET_TCP_CHECKSUMS #ifdef CONFIG_NET_TCP_CHECKSUMS
tcp->tcpchksum = ~tcp_ipv4_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
tcp->tcpchksum = ~tcp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_TCP);
tcp->tcpchksum = HTONS(chksum);
}
#endif #endif
#ifdef CONFIG_NET_STATISTICS #ifdef CONFIG_NET_STATISTICS
@@ -507,7 +526,17 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
tcp->tcpchksum = 0; tcp->tcpchksum = 0;
#ifdef CONFIG_NET_TCP_CHECKSUMS #ifdef CONFIG_NET_TCP_CHECKSUMS
tcp->tcpchksum = ~tcp_ipv6_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
tcp->tcpchksum = ~tcp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_TCP,
IPv6_HDRLEN);
tcp->tcpchksum = HTONS(chksum);
}
#endif #endif
} }
#endif /* CONFIG_NET_IPv6 */ #endif /* CONFIG_NET_IPv6 */
@@ -527,7 +556,16 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
tcp->tcpchksum = 0; tcp->tcpchksum = 0;
#ifdef CONFIG_NET_TCP_CHECKSUMS #ifdef CONFIG_NET_TCP_CHECKSUMS
tcp->tcpchksum = ~tcp_ipv4_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
tcp->tcpchksum = ~tcp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_TCP);
tcp->tcpchksum = HTONS(chksum);
}
#endif #endif
} }
#endif /* CONFIG_NET_IPv4 */ #endif /* CONFIG_NET_IPv4 */
+6 -2
View File
@@ -217,7 +217,7 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
unsigned int udpiplen; unsigned int udpiplen;
unsigned int udpdatalen = dev->d_len - iplen; unsigned int udpdatalen = dev->d_len - iplen;
#ifdef CONFIG_NET_UDP_CHECKSUMS #ifdef CONFIG_NET_UDP_CHECKSUMS
uint16_t chksum; uint16_t chksum = 0;
#endif #endif
int ret = OK; int ret = OK;
@@ -256,7 +256,11 @@ static int udp_input(FAR struct net_driver_s *dev, unsigned int iplen)
dev->d_appdata = IPBUF(udpiplen); dev->d_appdata = IPBUF(udpiplen);
#ifdef CONFIG_NET_UDP_CHECKSUMS #ifdef CONFIG_NET_UDP_CHECKSUMS
chksum = udp->udpchksum; if ((dev->d_features & NETDEV_RX_CSUM) == 0)
{
chksum = udp->udpchksum;
}
if (chksum != 0) if (chksum != 0)
{ {
#ifdef CONFIG_NET_IPv6 #ifdef CONFIG_NET_IPv6
+21 -2
View File
@@ -255,7 +255,16 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
if (IFF_IS_IPv4(dev->d_flags)) if (IFF_IS_IPv4(dev->d_flags))
#endif #endif
{ {
udp->udpchksum = ~udp_ipv4_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
udp->udpchksum = ~udp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_UDP);
udp->udpchksum = HTONS(chksum);
}
} }
#endif /* CONFIG_NET_IPv4 */ #endif /* CONFIG_NET_IPv4 */
@@ -264,7 +273,17 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
else else
#endif #endif
{ {
udp->udpchksum = ~udp_ipv6_chksum(dev); if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
udp->udpchksum = ~udp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_UDP,
IPv6_HDRLEN);
udp->udpchksum = HTONS(chksum);
}
} }
#endif /* CONFIG_NET_IPv6 */ #endif /* CONFIG_NET_IPv6 */