blob: edecc0705f4301eeb5cc6714136c7ccfc3ffff06 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <arpa/inet.h>
#include <netinet/icmp6.h>
#include <shill/net/byte_string.h>
#include <shill/net/ip_address.h>
#include <gtest/gtest.h>
#include "portier/ipv6_util.h"
namespace portier {
using shill::IPAddress;
using shill::ByteString;
using Code = Status::Code;
// Test data.
namespace {
// The zero packet.
const IPAddress kSourceAddress1 = IPAddress("::");
const IPAddress kDestinationAddress1 = IPAddress("::");
const uint8_t kNextHeader1 = 0;
const uint8_t kData1[] = {};
const uint16_t kExpectedChecksum1 = 0;
// A more realistic zero packet.
const IPAddress kSourceAddress2 = IPAddress("::");
const IPAddress kDestinationAddress2 =
IPAddress("ff02::1"); // All node link-local multicast.
const uint8_t kNextHeader2 = 59; // No next header. (0x3b)
const uint8_t kData2[] = {};
const uint16_t kExpectedChecksum2 = 0xff3e;
// All 1s (where valid) pseudo-header packet.
const IPAddress kSourceAddress3 =
IPAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
const IPAddress kDestinationAddress3 =
IPAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
const uint8_t kNextHeader3 = 0xff; // No next header. (0x3b)
const uint8_t kData3[] = {};
const uint16_t kExpectedChecksum3 = 0x00ff;
// ICMPv6 Echo Request
const IPAddress kSourceAddress4 =
IPAddress("2401:fa00:480:56:c1dd:402b:cc2f:7209");
const IPAddress kDestinationAddress4 = IPAddress("fe80::aef2:c5ff:fe71:17bf");
const uint8_t kNextHeader4 = 58; // ICMPv6.
// clang-format off
const uint8_t kData4[] = {
// Type=Echo Request (128), Code=0, Checksum=0.
0x80, 0x00, 0x00, 0x00,
// Id=1337, Sequence=9001.
0x05, 0x39, 0x23, 0x29,
// Data.
0x11, 0x22, 0x33, 0x44,
0x55, 0x66, 0x77, 0x88
};
// clang-format on
const uint16_t kExpectedChecksum4 = 0xa6c0;
// Odd byte length packet.
const IPAddress kSourceAddress5 = IPAddress("fe80::1");
const IPAddress kDestinationAddress5 = IPAddress("ff02::1");
const uint8_t kNextHeader5 = 58;
const uint8_t kData5[] = {0x11, 0x22, 0x33};
const uint16_t kExpectedChecksum5 = 0x41e5;
} // namespace
// Test using valid input.
TEST(IPv6UpperLayerChecksum16Test, ZeroPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress1, kDestinationAddress1,
kNextHeader1, kData1, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum1);
}
TEST(IPv6UpperLayerChecksum16Test, RealisticZeroPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress2, kDestinationAddress2,
kNextHeader2, kData2, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum2);
}
TEST(IPv6UpperLayerChecksum16Test, AllOnesPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress3, kDestinationAddress3,
kNextHeader3, kData3, 0, &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum3);
}
TEST(IPv6UpperLayerChecksum16Test, EchoRequestPacket) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress4, kDestinationAddress4,
kNextHeader4, kData4, sizeof(kData4), &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum4);
}
TEST(IPv6UpperLayerChecksum16Test, OddByteLength) {
uint16_t checksum = 0;
const Status status =
IPv6UpperLayerChecksum16(kSourceAddress5, kDestinationAddress5,
kNextHeader5, kData5, sizeof(kData5), &checksum);
EXPECT_TRUE(status);
EXPECT_EQ(ntohs(checksum), kExpectedChecksum5);
}
TEST(IPv6UpperLayerChecksum16Test, ChecksumProcess) {
// Create generic ICMPv6 header.
struct icmp6_hdr icmp6_hdr;
memset(&icmp6_hdr, 0, sizeof(icmp6_hdr));
icmp6_hdr.icmp6_type = ICMP6_DST_UNREACH;
icmp6_hdr.icmp6_data32[0] = 0x12345678;
// Calculate the checksum.
uint16_t checksum = 0;
Status status = IPv6UpperLayerChecksum16(
kSourceAddress5, kDestinationAddress5, kNextHeader5,
reinterpret_cast<const uint8_t*>(&icmp6_hdr), sizeof(icmp6_hdr),
&checksum);
EXPECT_TRUE(status);
// Provide the checksum to the ICMP header.
icmp6_hdr.icmp6_cksum = ~checksum;
// Recalculate.
status = IPv6UpperLayerChecksum16(
kSourceAddress5, kDestinationAddress5, kNextHeader5,
reinterpret_cast<const uint8_t*>(&icmp6_hdr), sizeof(icmp6_hdr),
&checksum);
EXPECT_TRUE(status);
EXPECT_EQ(checksum, 0);
}
} // namespace portier