summaryrefslogtreecommitdiffstats
path: root/src/lib/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/net.c')
-rw-r--r--src/lib/net.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/lib/net.c b/src/lib/net.c
new file mode 100644
index 0000000..7c899d7
--- /dev/null
+++ b/src/lib/net.c
@@ -0,0 +1,94 @@
+/*
+ * This program is is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2 of the
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ * @file net.c
+ * @brief Functions to parse raw packets.
+ *
+ * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ * @copyright 2014-2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+ #include <freeradius-devel/libradius.h>
+ #include <freeradius-devel/net.h>
+
+/** Calculate UDP checksum
+ *
+ * Zero out UDP checksum in UDP header before calling fr_udp_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the UDP header
+ * @param len value of udp length field in host byte order. Must be validated to make
+ * sure it won't overrun data buffer.
+ * @param checksum current checksum, leave as 0 to just enable validation.
+ * @param src_addr in network byte order.
+ * @param dst_addr in network byte order.
+ * @return 0 if the checksum is correct, else another number.
+ */
+uint16_t fr_udp_checksum(uint8_t const *data, uint16_t len, uint16_t checksum,
+ struct in_addr const src_addr, struct in_addr const dst_addr)
+{
+ uint64_t sum = 0; /* using 64bits avoids overflow check */
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint16_t const *ip_src = (void const *) &src_addr.s_addr;
+ uint16_t const *ip_dst = (void const *) &dst_addr.s_addr;
+ uint16_t i;
+
+ sum += *(ip_src++);
+ sum += *ip_src;
+ sum += *(ip_dst++);
+ sum += *ip_dst;
+
+ sum += htons(IPPROTO_UDP);
+ sum += htons(len);
+
+ for (i = len; i > 1; i -= 2) {
+ sum += *p++;
+ }
+
+ if (i) {
+ sum += (0xff & *(uint8_t const *)p) << 8;
+ }
+
+ sum -= checksum;
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ return ((uint16_t) ~sum);
+}
+
+/** Calculate IP header checksum.
+ *
+ * Zero out IP header checksum in IP header before calling fr_iph_checksum to get 'expected' checksum.
+ *
+ * @param data Pointer to the start of the IP header
+ * @param ihl value of ip header length field (number of 32 bit words)
+ */
+uint16_t fr_iph_checksum(uint8_t const *data, uint8_t ihl)
+{
+ uint64_t sum = 0;
+ uint16_t const *p = (uint16_t const *)data;
+
+ uint8_t nwords = (ihl << 1); /* number of 16-bit words */
+
+ for (sum = 0; nwords > 0; nwords--) {
+ sum += *p++;
+ }
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ return ((uint16_t) ~sum);
+}