/**************************************************************************** * 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 #include #include #include #include "netdev/netdev.h" /**************************************************************************** * 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 * ****************************************************************************/ #if defined(CONFIG_MM_IOB) && \ (defined(CONFIG_NET_IPv4) || defined(CONFIG_NET_IPv6)) 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; } #endif /**************************************************************************** * Name: hardware_chksum_get_proto * * Description: * get proto with dev. * * Input Parameters: * dev - The driver structure * * Returned Value: * The proto value * ****************************************************************************/ #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) static uint8_t hardware_chksum_get_proto(FAR struct net_driver_s *dev) { uint8_t proto = 0; #ifdef CONFIG_NET_IPv6 # ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(dev->d_flags)) # endif { FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; proto = ipv6->proto; } #endif #ifdef CONFIG_NET_IPv4 # ifdef CONFIG_NET_IPv6 else # endif { FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; proto = ipv4->proto; } #endif return proto; } #endif /**************************************************************************** * 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) { #ifdef CONFIG_MM_IOB int start = -EINVAL; #ifdef CONFIG_NET_IPv6 # ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(dev->d_flags)) # endif { 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; } } #endif #ifdef CONFIG_NET_IPv4 # ifdef CONFIG_NET_IPv6 else # endif { 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; } } #endif return start; #else return -EINVAL; #endif } /**************************************************************************** * 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) { #if defined(CONFIG_NET_UDP) || defined(CONFIG_NET_TCP) uint8_t proto = hardware_chksum_get_proto(dev); #endif #ifdef CONFIG_NET_UDP if (proto == IP_PROTO_UDP) { return offsetof(struct udp_hdr_s, udpchksum); } #endif #ifdef CONFIG_NET_TCP if (proto == IP_PROTO_TCP) { return offsetof(struct tcp_hdr_s, tcpchksum); } #endif return -EINVAL; } /**************************************************************************** * Name: netdev_upperlayer_header_checksum * * Description: * get upperlayer header checksum with tcp/udp header. * * Input Parameters: * dev - The driver structure * * Returned Value: * The upperlayer header checksum * ****************************************************************************/ uint16_t netdev_upperlayer_header_checksum(FAR struct net_driver_s *dev) { #ifdef CONFIG_NET_IPv6 # ifdef CONFIG_NET_IPv4 if (IFF_IS_IPv6(dev->d_flags)) # endif { FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; return HTONS(ipv6_upperlayer_header_chksum(dev, ipv6->proto, IPv6_HDRLEN)); } #endif #ifdef CONFIG_NET_IPv4 # ifdef CONFIG_NET_IPv6 else # endif { FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; return HTONS(ipv4_upperlayer_header_chksum(dev, ipv4->proto)); } #endif return 0; }