* $Id: libnet_checksum.c,v 1.1.1.1 2007/02/13 22:21:21 drp Exp $
* libnet_checksum.c - checksum routines
* Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
#include "../include/config.h"
#if (!(_WIN32) || (__CYGWIN__))
#include "../include/libnet.h"
#include "../include/win32/libnet.h"
libnet_in_cksum(u_int16_t
*addr
, int len
)
sum
+= *(u_int8_t
*)addr
<< 8;
libnet_toggle_checksum(libnet_t
*l
, libnet_ptag_t ptag
, int mode
)
p
= libnet_pblock_find(l
, ptag
);
/* err msg set in libnet_pblock_find() */
if ((p
->flags
) & LIBNET_PBLOCK_DO_CHECKSUM
)
(p
->flags
) |= LIBNET_PBLOCK_DO_CHECKSUM
;
if ((p
->flags
) & LIBNET_PBLOCK_DO_CHECKSUM
)
(p
->flags
) &= ~LIBNET_PBLOCK_DO_CHECKSUM
;
libnet_do_checksum(libnet_t
*l
, u_int8_t
*buf
, int protocol
, int len
)
/* will need to update this for ipv6 at some point */
struct libnet_ipv4_hdr
*iph_p
;
struct libnet_ipv6_hdr
*ip6h_p
;
is_ipv6
= 0; /* default to not using IPv6 */
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): header length can't be zero\n", __func__
);
* Figure out which IP version we're dealing with. We'll assume v4
* and overlay a header structure to yank out the version.
iph_p
= (struct libnet_ipv4_hdr
*)buf
;
if (iph_p
&& iph_p
->ip_v
== 6) {
ip6h_p
= (struct libnet_ipv6_hdr
*)buf
;
ip_hl
= iph_p
->ip_hl
<< 2;
* Dug Song came up with this very cool checksuming implementation
* eliminating the need for explicit psuedoheader use. Check it out.
struct libnet_sctp_hdr
*sctph_p
=
(struct libnet_sctp_hdr
*)(buf
+ ip_hl
);
sum
= libnet_sctp_cksum((u_int8_t
*)sctph_p
, len
);
* Style note: normally I don't advocate declaring variables inside
* blocks of control, but it makes good sense here. -- MDS
struct libnet_tcp_hdr
*tcph_p
=
(struct libnet_tcp_hdr
*)(buf
+ ip_hl
);
#if (STUPID_SOLARIS_CHECKSUM_BUG)
tcph_p
->th_sum
= tcph_p
->th_off
<< 2;
#endif /* STUPID_SOLARIS_CHECKSUM_BUG */
if (l
->injection_type
!= LIBNET_LINK
)
* Similiar to the Solaris Checksum bug - but need to add
* the size of the TCP payload (only for raw sockets).
tcph_p
->th_sum
= (tcph_p
->th_off
<< 2) +
(len
- (tcph_p
->th_off
<< 2));
sum
= libnet_in_cksum((u_int16_t
*)&ip6h_p
->ip_src
, 32);
sum
= libnet_in_cksum((u_int16_t
*)&iph_p
->ip_src
, 8);
sum
+= ntohs(IPPROTO_TCP
+ len
);
sum
+= libnet_in_cksum((u_int16_t
*)tcph_p
, len
);
tcph_p
->th_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_udp_hdr
*udph_p
=
(struct libnet_udp_hdr
*)(buf
+ ip_hl
);
sum
= libnet_in_cksum((u_int16_t
*)&ip6h_p
->ip_src
, 32);
sum
= libnet_in_cksum((u_int16_t
*)&iph_p
->ip_src
, 8);
sum
+= ntohs(IPPROTO_UDP
+ len
);
sum
+= libnet_in_cksum((u_int16_t
*)udph_p
, len
);
udph_p
->uh_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_icmpv4_hdr
*icmph_p
=
(struct libnet_icmpv4_hdr
*)(buf
+ ip_hl
);
sum
= libnet_in_cksum((u_int16_t
*)&ip6h_p
->ip_src
, 32);
sum
+= ntohs(IPPROTO_ICMP6
+ len
);
sum
+= libnet_in_cksum((u_int16_t
*)icmph_p
, len
);
icmph_p
->icmp_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_igmp_hdr
*igmph_p
=
(struct libnet_igmp_hdr
*)(buf
+ ip_hl
);
sum
= libnet_in_cksum((u_int16_t
*)igmph_p
, len
);
igmph_p
->igmp_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_rsvp_hdr
*rsvph_p
=
(struct libnet_rsvp_hdr
*)(buf
+ ip_hl
);
sum
= libnet_in_cksum((u_int16_t
*)rsvph_p
, len
);
rsvph_p
->checksum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_pim_hdr
*pim_p
=
(struct libnet_pim_hdr
*)(buf
+ ip_hl
);
if ((pim_p
->pim_ver_type
& 0x0f) == PIM_REGISTER
) {
sum
= libnet_in_cksum((u_int16_t
*)pim_p
, LIBNET_PIM_H
);
sum
= libnet_in_cksum((u_int16_t
*)pim_p
, len
);
pim_p
->pim_sum
= LIBNET_CKSUM_CARRY(sum
);
/* checksum is always at the same place in GRE header
* in the multiple RFC version of the protocol ... ouf !!!
struct libnet_gre_hdr
*greh_p
=
(struct libnet_gre_hdr
*)(buf
+ ip_hl
);
u_int16_t fv
= ntohs(greh_p
->flags_ver
);
if (!(fv
& (GRE_CSUM
|GRE_ROUTING
| GRE_VERSION_0
)) ||
!(fv
& (GRE_CSUM
|GRE_VERSION_1
)))
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): can't compute GRE checksum (wrong flags_ver bits: 0x%x )\n", __func__
, fv
);
sum
= libnet_in_cksum((u_int16_t
*)greh_p
, len
);
greh_p
->gre_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_ospf_hdr
*oh_p
=
(struct libnet_ospf_hdr
*)(buf
+ ip_hl
);
sum
+= libnet_in_cksum((u_int16_t
*)oh_p
, len
);
oh_p
->ospf_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_ospf_hdr
*oh_p
=
(struct libnet_ospf_hdr
*)(buf
+ ip_hl
);
struct libnet_lsa_hdr
*lsa_p
=
(struct libnet_lsa_hdr
*)(buf
+
sum
+= libnet_in_cksum((u_int16_t
*)lsa_p
, len
);
lsa_p
->lsa_sum
= LIBNET_CKSUM_CARRY(sum
);
* Reworked fletcher checksum taken from RFC 1008.
struct libnet_lsa_hdr
*lsa_p
= (struct libnet_lsa_hdr
*)buf
;
u_int8_t
*p
, *p1
, *p2
, *p3
;
p3
= buf
+ len
; /* beginning and end of buf */
for (p
= p1
; p
< p2
; p
++)
c1
%= 255; /* modular 255 */
#if AWR_PLEASE_REWORK_THIS
lsa_p
->lsa_cksum
[0] = (((len
- 17) * c0
- c1
) % 255);
if (lsa_p
->lsa_cksum
[0] <= 0)
lsa_p
->lsa_cksum
[0] += 255;
lsa_p
->lsa_cksum
[1] = (510 - c0
- lsa_p
->lsa_cksum
[0]);
if (lsa_p
->lsa_cksum
[1] > 255)
lsa_p
->lsa_cksum
[1] -= 255;
sum
= libnet_in_cksum((u_int16_t
*)iph_p
, ip_hl
);
iph_p
->ip_sum
= LIBNET_CKSUM_CARRY(sum
);
struct libnet_vrrp_hdr
*vrrph_p
=
(struct libnet_vrrp_hdr
*)(buf
+ ip_hl
);
sum
= libnet_in_cksum((u_int16_t
*)vrrph_p
, len
);
vrrph_p
->vrrp_sum
= LIBNET_CKSUM_CARRY(sum
);
{ /* XXX - Broken: how can we easily get the entire packet size? */
struct libnet_cdp_hdr
*cdph_p
=
(struct libnet_cdp_hdr
*)buf
;
sum
= libnet_in_cksum((u_int16_t
*)cdph_p
, len
);
cdph_p
->cdp_sum
= LIBNET_CKSUM_CARRY(sum
);
// struct libnet_isl_hdr *islh_p =
// (struct libnet_isl_hdr *)buf;
* Need to compute 4 byte CRC for the ethernet frame and for
* the ISL frame itself. Use the libnet_crc function.
snprintf(l
->err_buf
, LIBNET_ERRBUF_SIZE
,
"%s(): unsuported protocol %d\n", __func__
, protocol
);
libnet_ip_check(u_int16_t
*addr
, int len
)
sum
= libnet_in_cksum(addr
, len
);
return (LIBNET_CKSUM_CARRY(sum
));