Files
Ashin Walpola d107534eb2 Keep vanetza-idf in obu-firmware, so a plain clone builds the firmware
obu-firmware builds against the vanetza-idf C-ITS library, which until now
came from the colleague's microbu-esp32c5 tree beside the repository and was
not tracked here, so a clone of this repository could not build the firmware
it ships. The library alone is now part of obu-firmware, as
obu-firmware/external/vanetza-idf: their external/vanetza-idf at commit
cf4b99f, unchanged (9775 files; see its PROVENANCE.md). CMake takes it from
there by default; -DVANETZA_IDF_DIR still points the build elsewhere.

The rest of the colleague's tree (their own VAM firmware, PKI tooling,
station-link Python tools, the V2X2MAP bridge) stays out of this repository
and gitignored; nothing is pushed to their repository. NOTES.md, docs/06,
TODO.md and the pcap verifier's usage line point at the new location.
2026-09-24 10:56:05 +02:00

201 lines
7.3 KiB
C++

#include <gtest/gtest.h>
#include <vanetza/common/its_aid.hpp>
#include <vanetza/common/manual_runtime.hpp>
#include <vanetza/geonet/tests/fake_interfaces.hpp>
#include <vanetza/geonet/tests/security_context.hpp>
#include <vanetza/geonet/pdu_conversion.hpp>
#include <vanetza/geonet/pdu_variant.hpp>
#include <vanetza/geonet/router.hpp>
#include <vanetza/geonet/serialization_buffer.hpp>
#include <boost/variant/get.hpp>
using namespace vanetza;
using namespace vanetza::geonet;
class RouterRequest : public ::testing::Test
{
public:
RouterRequest() :
security(runtime), router(runtime, mib) {}
protected:
virtual void SetUp() override
{
mib.itsGnSecurity = true;
router.set_access_interface(&req_ifc);
router.set_security_entity(&security.entity());
router.set_transport_handler(geonet::UpperProtocol::IPv6, &ind_ifc);
test_payload[OsiLayer::Application] = ByteBuffer {47, 11, 1, 4, 42, 85};
}
std::unique_ptr<geonet::DownPacket> create_packet()
{
std::unique_ptr<DownPacket> packet { new DownPacket(test_payload) };
return packet;
}
ManagementInformationBase mib;
ManualRuntime runtime;
SecurityContext security;
Router router;
FakeRequestInterface req_ifc;
FakeTransportInterface ind_ifc;
ChunkPacket test_payload;
};
TEST_F(RouterRequest, router_request)
{
// create ShbDataRequest
ShbDataRequest request(mib, aid::CA);
request.upper_protocol = UpperProtocol::IPv6;
// Router handles request
auto confirm = router.request(request, create_packet());
EXPECT_TRUE(confirm.accepted());
// get the data from the fake network
ByteBuffer net_payload;
for (const auto layer : osi_layer_range<OsiLayer::Network, OsiLayer::Application>()) {
ByteBuffer tmp;
req_ifc.m_last_packet->layer(layer).convert(tmp);
std::copy(tmp.begin(), tmp.end(), std::back_inserter(net_payload));
}
UpPacket packet_up { CohesivePacket(net_payload, OsiLayer::Network) };
DownPacket packet_mac = *req_ifc.m_last_packet;
// all data should be in network layer: payload is encapsulated by secured message
EXPECT_EQ(packet_mac.size(), packet_mac[OsiLayer::Network].size());
// prepare access to network layer's PDU
using pdu_convertible = convertible::byte_buffer_impl<std::unique_ptr<Pdu>>;
pdu_convertible* pdu_conv = dynamic_cast<pdu_convertible*>(packet_mac[OsiLayer::Network].ptr());
ASSERT_TRUE(pdu_conv);
auto pdu = pdu_conv->m_pdu.get();
ASSERT_TRUE(pdu);
auto pdu_ext = dynamic_cast<ShbPdu*>(pdu);
ASSERT_TRUE(pdu_ext);
// check if packet has secured part
EXPECT_EQ(NextHeaderBasic::Secured, pdu->basic().next_header);
EXPECT_TRUE(pdu_ext->secured());
auto secured = *pdu_ext->secured();
// check payload of packet
auto secured2 = boost::get<security::v2::SecuredMessage>(&secured);
ASSERT_TRUE(secured2);
EXPECT_EQ(security::v2::PayloadType::Signed, secured2->payload.type);
EXPECT_EQ(test_payload.size(), pdu->common().payload);
const size_t payload_header_length = CommonHeader::length_bytes + ShbHeader::length_bytes;
EXPECT_EQ(payload_header_length, size(secured2->payload.data, OsiLayer::Network));
EXPECT_EQ(test_payload.size(), size(secured2->payload.data, OsiLayer::Transport, OsiLayer::Application));
ChunkPacket sec_payload = boost::get<ChunkPacket>(secured2->payload.data);
ChunkPacket sec_header = sec_payload.extract(OsiLayer::Network, OsiLayer::Network);
ByteBuffer actual_payload, expected_payload;
serialize_into_buffer(sec_payload, actual_payload);
serialize_into_buffer(test_payload, expected_payload);
EXPECT_EQ(expected_payload, actual_payload);
ByteBuffer actual_payload_header, expected_payload_header;
geonet::serialize_into_buffer(pdu_ext->common(), expected_payload_header);
geonet::serialize_into_buffer(pdu_ext->extended(), expected_payload_header);
sec_header[OsiLayer::Network].convert(actual_payload_header);
EXPECT_EQ(expected_payload_header, actual_payload_header);
}
TEST_F(RouterRequest, modified_request_maximum_lifetime)
{
// create ShbDataRequest
ShbDataRequest request(mib, aid::CA);
// create new Lifetime that is larger than the itsGnMaxPacketLifetime of mib
Lifetime large_lifetime(Lifetime::Base::Hundred_Seconds, 9);
request.maximum_lifetime = large_lifetime;
request.upper_protocol = UpperProtocol::IPv6;
// Router handles request
auto confirm = router.request(request, create_packet());
EXPECT_EQ(DataConfirm::ResultCode::Rejected_Max_Lifetime, confirm.result_code);
}
TEST_F(RouterRequest, modified_request_repetition)
{
// create ShbDataRequest
ShbDataRequest request(mib, aid::CA);
// create durations that will fail in data_confirm
auto rep_faulty_int = 0.0 * units::si::seconds; // this has to be lower than mib.itsGnMinPacketRepetitionInterval
auto rep_max = 99.0 * units::si::seconds;
// create Repetition with faulty interval
DataRequest::Repetition rep;
rep.interval = rep_faulty_int;
rep.maximum = rep_max;
request.repetition = rep;
request.upper_protocol = UpperProtocol::IPv6;
// Router handles request
auto confirm = router.request(request, create_packet());
EXPECT_EQ(DataConfirm::ResultCode::Rejected_Min_Repetition_Interval, confirm.result_code);
}
TEST_F(RouterRequest, modified_request_payload_null)
{
// create ShbDataRequest
ShbDataRequest request(mib, aid::CA);
request.upper_protocol = UpperProtocol::IPv6;
// Router handles request
auto confirm = router.request(request, nullptr);
EXPECT_EQ(DataConfirm::ResultCode::Rejected_Unspecified, confirm.result_code);
}
TEST_F(RouterRequest, modified_request_large_payload)
{
std::unique_ptr<geonet::DownPacket> packet { new geonet::DownPacket() };
// create too large payload
ByteBuffer payload_large;
for (int i = 0; i < 1000; i++) {
ByteBuffer tmp = {0,1,2,3,4,5,6,7,8,9};
payload_large.insert(payload_large.end(), tmp.begin(), tmp.end());
}
// insert payload in packet
packet->layer(OsiLayer::Transport) = ByteBuffer(payload_large);
// create ShbDataRequest
ShbDataRequest request(mib, aid::CA);
request.upper_protocol = UpperProtocol::IPv6;
// Router handles request
auto confirm = router.request(request, std::move(packet));
EXPECT_EQ(DataConfirm::ResultCode::Rejected_Max_SDU_Size, confirm.result_code);
}
TEST_F(RouterRequest, shb_repetition)
{
ShbDataRequest request(mib, aid::CA);
request.repetition = DataRequest::Repetition {
0.1 * units::si::seconds, 10.0 * units::si::seconds
};
EXPECT_EQ(0, req_ifc.m_requests);
auto confirm = router.request(request, create_packet());
EXPECT_EQ(DataConfirm::ResultCode::Accepted, confirm.result_code);
EXPECT_EQ(1, req_ifc.m_requests);
ASSERT_TRUE(!!req_ifc.m_last_packet);
// length of network layer is excluded because of varying secured message header fields
const auto payload_size = size(*req_ifc.m_last_packet, OsiLayer::Transport, OsiLayer::Application);
// trigger five repetitions
for (unsigned i = 0; i < 5; ++i) {
runtime.trigger(std::chrono::milliseconds(100));
}
EXPECT_EQ(6, req_ifc.m_requests);
EXPECT_EQ(payload_size, size(*req_ifc.m_last_packet, OsiLayer::Transport, OsiLayer::Application));
}