/* * 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 * @copyright 2014-2015 Arran Cudbard-Bell */ #include #include /** 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); }