Annotation of embedaddon/libnet/src/libnet_checksum.c, revision 1.1
1.1 ! misho 1: /*
! 2: * $Id: libnet_checksum.c,v 1.13 2004/03/01 20:26:12 mike Exp $
! 3: *
! 4: * libnet
! 5: * libnet_checksum.c - checksum routines
! 6: *
! 7: * Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
! 8: * All rights reserved.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: *
! 19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 22: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 29: * SUCH DAMAGE.
! 30: *
! 31: */
! 32:
! 33: #if (HAVE_CONFIG_H)
! 34: #include "../include/config.h"
! 35: #endif
! 36: #if (!(_WIN32) || (__CYGWIN__))
! 37: #include "../include/libnet.h"
! 38: #else
! 39: #include "../include/win32/libnet.h"
! 40: #endif
! 41: int
! 42: libnet_in_cksum(u_int16_t *addr, int len)
! 43: {
! 44: int sum;
! 45:
! 46: sum = 0;
! 47:
! 48: while (len > 1)
! 49: {
! 50: sum += *addr++;
! 51: len -= 2;
! 52: }
! 53: if (len == 1)
! 54: {
! 55: sum += *(u_int16_t *)addr;
! 56: }
! 57:
! 58: return (sum);
! 59: }
! 60:
! 61: int
! 62: libnet_toggle_checksum(libnet_t *l, libnet_ptag_t ptag, int mode)
! 63: {
! 64: libnet_pblock_t *p;
! 65:
! 66: p = libnet_pblock_find(l, ptag);
! 67: if (p == NULL)
! 68: {
! 69: /* err msg set in libnet_pblock_find() */
! 70: return (-1);
! 71: }
! 72: if (mode == LIBNET_ON)
! 73: {
! 74: if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
! 75: {
! 76: return (1);
! 77: }
! 78: else
! 79: {
! 80: (p->flags) |= LIBNET_PBLOCK_DO_CHECKSUM;
! 81: return (1);
! 82: }
! 83: }
! 84: else
! 85: {
! 86: if ((p->flags) & LIBNET_PBLOCK_DO_CHECKSUM)
! 87: {
! 88: (p->flags) &= ~LIBNET_PBLOCK_DO_CHECKSUM;
! 89: return (1);
! 90: }
! 91: else
! 92: {
! 93: return (1);
! 94: }
! 95: }
! 96: }
! 97:
! 98:
! 99: int
! 100: libnet_do_checksum(libnet_t *l, u_int8_t *buf, int protocol, int len)
! 101: {
! 102: /* will need to update this for ipv6 at some point */
! 103: struct libnet_ipv4_hdr *iph_p;
! 104: struct libnet_ipv6_hdr *ip6h_p;
! 105: int is_ipv6;
! 106: int ip_hl;
! 107: int sum;
! 108:
! 109: is_ipv6 = 0; /* default to not using IPv6 */
! 110: sum = 0;
! 111: iph_p = NULL;
! 112: ip6h_p = NULL;
! 113:
! 114: if (len == 0)
! 115: {
! 116: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 117: "%s(): header length can't be zero\n", __func__);
! 118: return (-1);
! 119: }
! 120:
! 121: /*
! 122: * Figure out which IP version we're dealing with. We'll assume v4
! 123: * and overlay a header structure to yank out the version.
! 124: */
! 125: iph_p = (struct libnet_ipv4_hdr *)buf;
! 126: if (iph_p && iph_p->ip_v == 6)
! 127: {
! 128: ip6h_p = (struct libnet_ipv6_hdr *)buf;
! 129: is_ipv6 = 1;
! 130: ip_hl = 40;
! 131: }
! 132: else
! 133: {
! 134: is_ipv6 = 0;
! 135: ip_hl = iph_p->ip_hl << 2;
! 136: }
! 137:
! 138: /*
! 139: * Dug Song came up with this very cool checksuming implementation
! 140: * eliminating the need for explicit psuedoheader use. Check it out.
! 141: */
! 142: switch (protocol)
! 143: {
! 144: /*
! 145: * Style note: normally I don't advocate declaring variables inside
! 146: * blocks of control, but it makes good sense here. -- MDS
! 147: */
! 148: case IPPROTO_TCP:
! 149: {
! 150: struct libnet_tcp_hdr *tcph_p =
! 151: (struct libnet_tcp_hdr *)(buf + ip_hl);
! 152:
! 153: #if (STUPID_SOLARIS_CHECKSUM_BUG)
! 154: tcph_p->th_sum = tcph_p->th_off << 2;
! 155: return (1);
! 156: #endif /* STUPID_SOLARIS_CHECKSUM_BUG */
! 157: #if (HAVE_HPUX11)
! 158: if (l->injection_type != LIBNET_LINK)
! 159: {
! 160: /*
! 161: * Similiar to the Solaris Checksum bug - but need to add
! 162: * the size of the TCP payload (only for raw sockets).
! 163: */
! 164: tcph_p->th_sum = (tcph_p->th_off << 2) +
! 165: (len - (tcph_p->th_off << 2));
! 166: return (1);
! 167: }
! 168: #endif
! 169: tcph_p->th_sum = 0;
! 170: if (is_ipv6)
! 171: {
! 172: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
! 173: }
! 174: else
! 175: {
! 176: sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
! 177: }
! 178: sum += ntohs(IPPROTO_TCP + len);
! 179: sum += libnet_in_cksum((u_int16_t *)tcph_p, len);
! 180: tcph_p->th_sum = LIBNET_CKSUM_CARRY(sum);
! 181: break;
! 182: }
! 183: case IPPROTO_UDP:
! 184: {
! 185: struct libnet_udp_hdr *udph_p =
! 186: (struct libnet_udp_hdr *)(buf + ip_hl);
! 187: udph_p->uh_sum = 0;
! 188: if (is_ipv6)
! 189: {
! 190: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
! 191: }
! 192: else
! 193: {
! 194: sum = libnet_in_cksum((u_int16_t *)&iph_p->ip_src, 8);
! 195: }
! 196: sum += ntohs(IPPROTO_UDP + len);
! 197: sum += libnet_in_cksum((u_int16_t *)udph_p, len);
! 198: udph_p->uh_sum = LIBNET_CKSUM_CARRY(sum);
! 199: break;
! 200: }
! 201: case IPPROTO_ICMP:
! 202: {
! 203: struct libnet_icmpv4_hdr *icmph_p =
! 204: (struct libnet_icmpv4_hdr *)(buf + ip_hl);
! 205:
! 206: icmph_p->icmp_sum = 0;
! 207: if (is_ipv6)
! 208: {
! 209: sum = libnet_in_cksum((u_int16_t *)&ip6h_p->ip_src, 32);
! 210: sum += ntohs(IPPROTO_ICMP6 + len);
! 211: }
! 212: sum += libnet_in_cksum((u_int16_t *)icmph_p, len);
! 213: icmph_p->icmp_sum = LIBNET_CKSUM_CARRY(sum);
! 214: break;
! 215: }
! 216: case IPPROTO_IGMP:
! 217: {
! 218: struct libnet_igmp_hdr *igmph_p =
! 219: (struct libnet_igmp_hdr *)(buf + ip_hl);
! 220:
! 221: igmph_p->igmp_sum = 0;
! 222: sum = libnet_in_cksum((u_int16_t *)igmph_p, len);
! 223: igmph_p->igmp_sum = LIBNET_CKSUM_CARRY(sum);
! 224: break;
! 225: }
! 226: case IPPROTO_GRE:
! 227: {
! 228: /* checksum is always at the same place in GRE header
! 229: * in the multiple RFC version of the protocol ... ouf !!!
! 230: */
! 231: struct libnet_gre_hdr *greh_p =
! 232: (struct libnet_gre_hdr *)(buf + ip_hl);
! 233: u_int16_t fv = ntohs(greh_p->flags_ver);
! 234: if (!(fv & (GRE_CSUM|GRE_ROUTING | GRE_VERSION_0)) ||
! 235: !(fv & (GRE_CSUM|GRE_VERSION_1)))
! 236: {
! 237: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 238: "%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__, fv);
! 239: return (-1);
! 240: }
! 241: sum = libnet_in_cksum((u_int16_t *)greh_p, len);
! 242: greh_p->gre_sum = LIBNET_CKSUM_CARRY(sum);
! 243: break;
! 244: }
! 245: case IPPROTO_OSPF:
! 246: {
! 247: struct libnet_ospf_hdr *oh_p =
! 248: (struct libnet_ospf_hdr *)(buf + ip_hl);
! 249:
! 250: oh_p->ospf_sum = 0;
! 251: sum += libnet_in_cksum((u_int16_t *)oh_p, len);
! 252: oh_p->ospf_sum = LIBNET_CKSUM_CARRY(sum);
! 253: break;
! 254: }
! 255: case IPPROTO_OSPF_LSA:
! 256: {
! 257: struct libnet_ospf_hdr *oh_p =
! 258: (struct libnet_ospf_hdr *)(buf + ip_hl);
! 259: struct libnet_lsa_hdr *lsa_p =
! 260: (struct libnet_lsa_hdr *)(buf +
! 261: ip_hl + oh_p->ospf_len);
! 262:
! 263: lsa_p->lsa_sum = 0;
! 264: sum += libnet_in_cksum((u_int16_t *)lsa_p, len);
! 265: lsa_p->lsa_sum = LIBNET_CKSUM_CARRY(sum);
! 266: break;
! 267: #if 0
! 268: /*
! 269: * Reworked fletcher checksum taken from RFC 1008.
! 270: */
! 271: int c0, c1;
! 272: struct libnet_lsa_hdr *lsa_p = (struct libnet_lsa_hdr *)buf;
! 273: u_int8_t *p, *p1, *p2, *p3;
! 274:
! 275: c0 = 0;
! 276: c1 = 0;
! 277:
! 278: lsa_p->lsa_cksum = 0;
! 279:
! 280: p = buf;
! 281: p1 = buf;
! 282: p3 = buf + len; /* beginning and end of buf */
! 283:
! 284: while (p1 < p3)
! 285: {
! 286: p2 = p1 + LIBNET_MODX;
! 287: if (p2 > p3)
! 288: {
! 289: p2 = p3;
! 290: }
! 291:
! 292: for (p = p1; p < p2; p++)
! 293: {
! 294: c0 += (*p);
! 295: c1 += c0;
! 296: }
! 297:
! 298: c0 %= 255;
! 299: c1 %= 255; /* modular 255 */
! 300:
! 301: p1 = p2;
! 302: }
! 303:
! 304: #if AWR_PLEASE_REWORK_THIS
! 305: lsa_p->lsa_cksum[0] = (((len - 17) * c0 - c1) % 255);
! 306: if (lsa_p->lsa_cksum[0] <= 0)
! 307: {
! 308: lsa_p->lsa_cksum[0] += 255;
! 309: }
! 310:
! 311: lsa_p->lsa_cksum[1] = (510 - c0 - lsa_p->lsa_cksum[0]);
! 312: if (lsa_p->lsa_cksum[1] > 255)
! 313: {
! 314: lsa_p->lsa_cksum[1] -= 255;
! 315: }
! 316: #endif
! 317: break;
! 318: #endif
! 319: }
! 320: case IPPROTO_IP:
! 321: {
! 322: iph_p->ip_sum = 0;
! 323: sum = libnet_in_cksum((u_int16_t *)iph_p, ip_hl);
! 324: iph_p->ip_sum = LIBNET_CKSUM_CARRY(sum);
! 325: break;
! 326: }
! 327: case IPPROTO_VRRP:
! 328: {
! 329: struct libnet_vrrp_hdr *vrrph_p =
! 330: (struct libnet_vrrp_hdr *)(buf + ip_hl);
! 331:
! 332: vrrph_p->vrrp_sum = 0;
! 333: sum = libnet_in_cksum((u_int16_t *)vrrph_p, len);
! 334: vrrph_p->vrrp_sum = LIBNET_CKSUM_CARRY(sum);
! 335: break;
! 336: }
! 337: case LIBNET_PROTO_CDP:
! 338: { /* XXX - Broken: how can we easily get the entire packet size? */
! 339: struct libnet_cdp_hdr *cdph_p =
! 340: (struct libnet_cdp_hdr *)buf;
! 341:
! 342: cdph_p->cdp_sum = 0;
! 343: sum = libnet_in_cksum((u_int16_t *)cdph_p, len);
! 344: cdph_p->cdp_sum = LIBNET_CKSUM_CARRY(sum);
! 345: break;
! 346: }
! 347: case LIBNET_PROTO_ISL:
! 348: {
! 349: // struct libnet_isl_hdr *islh_p =
! 350: // (struct libnet_isl_hdr *)buf;
! 351: /*
! 352: * Need to compute 4 byte CRC for the ethernet frame and for
! 353: * the ISL frame itself. Use the libnet_crc function.
! 354: */
! 355: }
! 356: default:
! 357: {
! 358: snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
! 359: "%s(): unsuported protocol %d\n", __func__, protocol);
! 360: return (-1);
! 361: }
! 362: }
! 363: return (1);
! 364: }
! 365:
! 366:
! 367: u_int16_t
! 368: libnet_ip_check(u_int16_t *addr, int len)
! 369: {
! 370: int sum;
! 371:
! 372: sum = libnet_in_cksum(addr, len);
! 373: return (LIBNET_CKSUM_CARRY(sum));
! 374: }
! 375:
! 376: /* EOF */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>