summaryrefslogtreecommitdiffstats
path: root/src/checksums.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/checksums.c')
-rw-r--r--src/checksums.c229
1 files changed, 229 insertions, 0 deletions
diff --git a/src/checksums.c b/src/checksums.c
new file mode 100644
index 0000000..852f195
--- /dev/null
+++ b/src/checksums.c
@@ -0,0 +1,229 @@
+/*---------------------------------------------------------------
+ * Copyright (c) 2018
+ * Broadcom Corporation
+ * All Rights Reserved.
+ *---------------------------------------------------------------
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated
+ * documentation files (the "Software"), to deal in the Software
+ * without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit
+ * persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ *
+ * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and
+ * the following disclaimers.
+ *
+ *
+ * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimers in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ *
+ * Neither the name of Broadcom Coporation,
+ * nor the names of its contributors may be used to endorse
+ * or promote products derived from this Software without
+ * specific prior written permission.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ * ________________________________________________________________
+ *
+ * UDP checksums v4 and v6
+ *
+ * The checksum calculation is defined in RFC 768
+ * hints as to how to calculate it efficiently are in RFC 1071
+ *
+ * by Robert J. McMahon (rjmcmahon@rjmcmahon.com, bob.mcmahon@broadcom.com)
+ * -------------------------------------------------------------------
+ */
+#include "headers.h"
+
+/*
+ *
+ * Compute Internet Checksum for UDP packets (assumes 32 bit system)
+ *
+ * IPV4 Notes:
+ *
+ * User Datagram Header Format
+ * 0 7 8 15 16 23 24 31
+ * +--------+--------+--------+--------+
+ * | Source | Destination |
+ * | Port | Port |
+ * +--------+--------+--------+--------+
+ * | | |
+ * | Length | Checksum |
+ * +--------+--------+--------+--------+
+ * |
+ * | data octets ...
+ * +---------------- ...
+ *
+ *
+ * Checksum is the 16-bit one's complement of the one's complement sum of a
+ * pseudo header of information from the IP header, the UDP header, and the
+ * data, padded with zero octets at the end (if necessary) to make a
+ * multiple of two octets.
+ *
+ * The ipv4 pseudo header conceptually prefixed to the UDP header contains the
+ * source address, the destination address, the protocol, and the UDP
+ * length. This information gives protection against misrouted datagrams.
+ * This checksum procedure is the same as is used in TCP.
+ *
+ * 0 7 8 15 16 23 24 31
+ * +--------+--------+--------+--------+
+ * | source address |
+ * +--------+--------+--------+--------+
+ * | destination address |
+ * +--------+--------+--------+--------+
+ * | zero |protocol| UDP length |
+ * +--------+--------+--------+--------+
+ *
+ * If the computed checksum is zero, it is transmitted as all ones (the
+ * equivalent in one's complement arithmetic). An all zero transmitted
+ * checksum value means that the transmitter generated no checksum (for
+ * debugging or for higher level protocols that don't care).
+ *
+ *
+ * IPV6 Notes:
+ *
+ * Any transport or other upper-layer protocol that includes the
+ * addresses from the IP header in its checksum computation must be
+ * modified for use over IPv6, to include the 128-bit IPv6 addresses
+ * instead of 32-bit IPv4 addresses. In particular, the following
+ * illustration shows the TCP and UDP "pseudo-header" for IPv6:
+ *
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + +
+ * | |
+ * + Source Address +
+ * | |
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | |
+ * + +
+ * | |
+ * + Destination Address +
+ * | |
+ * + +
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Upper-Layer Packet Length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | zero | Next Header |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * o If the IPv6 packet contains a Routing header, the Destination
+ * Address used in the pseudo-header is that of the final
+ * destination. At the originating node, that address will be in
+ * the last element of the Routing header; at the recipient(s),
+ * that address will be in the Destination Address field of the
+ * IPv6 header.
+ *
+ * o The Next Header value in the pseudo-header identifies the
+ * upper-layer protocol (e.g., 6 for TCP, or 17 for UDP). It will
+ * differ from the Next Header value in the IPv6 header if there
+ * are extension headers between the IPv6 header and the upper-
+ * layer header.
+ *
+ * o The Upper-Layer Packet Length in the pseudo-header is the
+ * length of the upper-layer header and data (e.g., TCP header
+ * plus TCP data). Some upper-layer protocols carry their own
+ * length information (e.g., the Length field in the UDP header);
+ * for such protocols, that is the length used in the pseudo-
+ * header. Other protocols (such as TCP) do not carry their own
+ * length information, in which case the length used in the
+ * pseudo-header is the Payload Length from the IPv6 header, minus
+ * the length of any extension headers present between the IPv6
+ * header and the upper-layer header.
+ *
+ * o Unlike IPv4, when UDP packets are originated by an IPv6 node,
+ * the UDP checksum is not optional. That is, whenever
+ * originating a UDP packet, an IPv6 node must compute a UDP
+ * checksum over the packet and the pseudo-header, and, if that
+ * computation yields a result of zero, it must be changed to hex
+ * FFFF for placement in the UDP header. IPv6 receivers must
+ * discard UDP packets containing a zero checksum, and should log
+ * the error.
+ *
+ *
+ * Returns zero on checksum success, non zero otherwise
+ */
+
+#define IPV4SRCOFFSET 12 // the ipv4 source address offset from the l3 pdu
+#define IPV6SRCOFFSET 8 // the ipv6 source address offset
+#define IPV6SIZE 8 // units is number of 16 bits, i.e. 128 bits is eight 16 bits
+#define IPV4SIZE 2 // v4 is two 16 bits (32 bits)
+#define UDPPROTO 17 // UDP protocol value for psuedo header
+uint32_t udpchecksum(const void *l3pdu, const void *l4pdu, int udplen, int v6) {
+ register uint32_t sum = 0;
+ const uint16_t *data;
+ int i;
+
+ const struct udphdr *udp_hdr = (const struct udphdr *)l4pdu;
+ if (!udp_hdr->check) {
+ if (v6)
+ // v6 requires checksums
+ return -1;
+ else
+ // v4 checksums are optional
+ return 0;
+ }
+
+ /*
+ * Build pseudo headers, partially from the packet
+ * (which are in network byte order) and
+ * the protocol of UDP (value of 17). Also, the IP dst
+ * addr immediately follows the src so double the size
+ * per each loop to cover both addrs
+ */
+ if (v6) {
+ // skip to the ip header v6 src field, offset 8 (see ipv6 header)
+ data = (const uint16_t *)((char *)l3pdu + IPV6SRCOFFSET);
+ for (i = 0; i < (2 * IPV6SIZE); i++) {
+ sum += *data++;
+ }
+ } else {
+ // skip to the ip header v4 src field, offset 12 (see ipv4 header)
+ data = (const uint16_t *)((char *)l3pdu + IPV4SRCOFFSET);
+ for (i = 0; i < (2 * IPV4SIZE); i++) {
+ sum += *data++;
+ }
+ }
+ // These should work for both v4 and v6 even though
+ // v6 psuedo header uses 32 bit values because the
+ // uppers in v6 will be zero
+ sum += htons(UDPPROTO); // proto of UDP is 17
+ sum += htons(udplen); // For UDP, the pseudo hdr len equals udp len
+
+ /*
+ * UDP hdr + payload
+ */
+ data = (const uint16_t *) l4pdu;
+ while( udplen > 1 ) {
+ sum += *data++;
+ udplen -= 2;
+ }
+ /* Add left-over byte, if any */
+ if( udplen > 0 )
+ sum += * (uint8_t *) data;
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum>>16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ /* return ones complement */
+ sum = (sum ^ 0xffff);
+ return sum;
+}