Example #1
0
/*
 * Adjust the checksum value of an ICMP/ICMPv6 packet, based on the
 * original type/code values and new type/code values.
 */
int
cksum_update_icmp_type_code(void *icmp46_hdrp, int orig_type, int orig_code,
			    int new_type, int new_code)
{
  assert(icmp46_hdrp != NULL);

  struct icmp6_hdr *icmp6_hdrp = icmp46_hdrp;
  int32_t sum = icmp6_hdrp->icmp6_cksum;
  sum = ~sum & 0xffff;
  uint8_t typecode[2];

  /* Subtract the original type/code values from the checksum value. */
  typecode[0] = orig_type;
  typecode[1] = orig_code;
  sum -= cksum_acc_words((const uint16_t *)typecode, 2);

  /* Add the new type/code values to the checksum value. */
  typecode[0] = new_type;
  typecode[1] = new_code;
  sum += cksum_acc_words((const uint16_t *)typecode, 2);

  ADDCARRY(sum);
  icmp6_hdrp->icmp6_cksum = ~sum & 0xffff;

  return (0);
}
Example #2
0
u_short
in_addword(u_short a, u_short b)
{
	u_int64_t sum = a + b;

	ADDCARRY(sum);
	return (sum);
}
Example #3
0
/*
 * Calculate the transport layer checksum value.  The parameter must
 * contain the entire packet to calculate the sum.
 *
 * The ulp parameter contains the transport protocol number.  The iov
 * parameter contains the following information.
 *
 * iov[0]: Address family (uint32_t), or struct tun_pi{}
 * iov[1]: IPv4/IPv6 header
 * iov[2]: IPv6 Fragment header (if necessary, otherwise NULL)
 * iov[3]: Upper layer protocol header
 * iov[4]: Upper layer protocol data
 */
int
cksum_calc_ulp(int ulp, struct iovec *iov)
{
  assert(iov != NULL);
  assert(iov[0].iov_base != NULL);
  assert(iov[1].iov_base != NULL);
  assert(iov[3].iov_base != NULL);

  int32_t sum;
  struct icmp *icmp4_hdrp;
  struct icmp6_hdr *icmp6_hdrp;
  switch (ulp) {
  case IPPROTO_ICMP:
    icmp4_hdrp = iov[3].iov_base;
    icmp4_hdrp->icmp_cksum = 0;
    sum = cksum_acc_words(iov[3].iov_base, iov[3].iov_len);
    if (iov[4].iov_base != NULL) {
      sum += cksum_acc_words(iov[4].iov_base, iov[4].iov_len);
    }
    ADDCARRY(sum);
    icmp4_hdrp->icmp_cksum = ~sum & 0xffff;
    break;

  case IPPROTO_ICMPV6:
    icmp6_hdrp = iov[3].iov_base;
    icmp6_hdrp->icmp6_cksum = 0;
    sum = cksum_acc_ip_pheader(iov[1].iov_base);
    sum += cksum_acc_words(iov[3].iov_base, iov[3].iov_len);
    if (iov[4].iov_base != NULL) {
      sum += cksum_acc_words(iov[4].iov_base, iov[4].iov_len);
    }
    ADDCARRY(sum);
    icmp6_hdrp->icmp6_cksum = ~sum & 0xfff;
    break;

  default:
    warnx("unsupported upper layer protocol %d.", ulp);
    return (-1);
  }

  return (0);
}
Example #4
0
/* Calculate the checksum value of an IPv4 header. */
uint16_t
cksum_calc_ip4_header(const struct ip *ip4_hdrp)
{
  assert(ip4_hdrp != NULL);

  int32_t sum = 0;
  int ip4_header_len = ip4_hdrp->ip_hl << 2;
  sum = cksum_acc_words((uint16_t *)ip4_hdrp, ip4_header_len);
  ADDCARRY(sum);

  return (~sum & 0xffff);
}
Example #5
0
/*
 * Adjust the transport layer checksum value based on the difference
 * between the incoming IP header and the outgoing IP header values,
 * and update the checksum field appropriately.
 *
 * The ulp parameter contains the transport protocol number.  The
 * orig_ip_hdrp parameter points the incoming IP header. The iov
 * parameter contains the following information.
 *
 * iov[0]: Address family (uint32_t), or struct tun_pi{}
 * iov[1]: IPv4/IPv6 header
 * iov[2]: IPv6 Fragment header (if necessary, otherwise NULL)
 * iov[3]: Upper layer protocol data (at least, a header must exist)
 */
int
cksum_update_ulp(int ulp, const void *orig_ip_hdrp, struct iovec *iov)
{
  assert(orig_ip_hdrp != NULL);
  assert(iov != NULL);
  assert(iov[0].iov_base != NULL);
  assert(iov[1].iov_base != NULL);
  assert(iov[3].iov_base != NULL);

  struct tcphdr *tcp_hdrp;
  struct udphdr *udp_hdrp;
  struct icmp *icmp_hdrp;
  struct icmp6_hdr *icmp6_hdrp;
  int32_t sum;
  switch (ulp) {
  case IPPROTO_ICMP:
    icmp_hdrp = iov[3].iov_base;
    sum = icmp_hdrp->icmp_cksum;
    sum = ~sum & 0xffff;
    sum -= cksum_acc_ip_pheader(orig_ip_hdrp);
    /*
     * ICMPv6 includes the sum of the pseudo IPv6 header in its
     * checksum calculation, but ICMP doesn't.  We just subtract the
     * original pseudo IPv6 header sum from the checksum value.
     */
    ADDCARRY(sum);
    icmp_hdrp->icmp_cksum = ~sum & 0xffff;
    break;

  case IPPROTO_ICMPV6:
    icmp6_hdrp = iov[3].iov_base;
    sum = icmp6_hdrp->icmp6_cksum;
    sum = ~sum & 0xffff;
    sum += cksum_acc_ip_pheader(iov[1].iov_base);
    /*
     * Similar to the ICMP case above, we just add the new pseudo IPv6
     * header sum to the checksum value, since the original ICMP
     * checksum doesn't include the IP pseudo header sum.
     */
    ADDCARRY(sum);
    icmp6_hdrp->icmp6_cksum = ~sum & 0xffff;
    break;

#if defined(__linux__)
#define th_sum check
#define uh_sum check
#endif
  case IPPROTO_TCP:
    tcp_hdrp = iov[3].iov_base;
    sum = tcp_hdrp->th_sum;
    sum = ~sum & 0xffff;
    sum -= cksum_acc_ip_pheader_wo_payload_len(orig_ip_hdrp);
    sum += cksum_acc_ip_pheader_wo_payload_len(iov[1].iov_base);
    ADDCARRY(sum);
    tcp_hdrp->th_sum = ~sum & 0xffff;
    break;

  case IPPROTO_UDP:
    udp_hdrp = iov[3].iov_base;
    sum = udp_hdrp->uh_sum;
    sum = ~sum & 0xffff;
    sum -= cksum_acc_ip_pheader_wo_payload_len(orig_ip_hdrp);
    sum += cksum_acc_ip_pheader_wo_payload_len(iov[1].iov_base);
    ADDCARRY(sum);
    udp_hdrp->uh_sum = ~sum & 0xffff;
    break;
#if defined(__linux__)
#undef th_sum
#undef uh_sum
#endif

  default:
    warnx("unsupported upper layer protocol %d.", ulp);
    return (-1);
  }

  return (0);
}