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

143 lines
5.2 KiB
C++

#include "link_layer.hpp"
#include "raw_socket_link.hpp"
#include "tcp_link.hpp"
#include "udp_link.hpp"
#include <vanetza/access/ethertype.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/generic/raw_protocol.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/asio/ip/udp.hpp>
#include <iostream>
#ifdef SOCKTAP_WITH_CUBE_EVK
# include "nfiniity_cube_evk_link.hpp"
#endif
#ifdef SOCKTAP_WITH_COHDA_LLC
# include "cohda_link.hpp"
#endif
#ifdef SOCKTAP_WITH_AUTOTALKS
# include "autotalks_link.hpp"
# include "autotalks.hpp"
#endif
#ifdef SOCKTAP_WITH_RPC
# include "rpc_link.hpp"
#endif
boost::optional<std::pair<boost::asio::ip::address, unsigned short>> parse_ip_port(const std::string& ip_port)
{
using opt_ip_port = boost::optional<std::pair<boost::asio::ip::address, unsigned short>>;
std::size_t ip_len = ip_port.find_last_of(":");
if (ip_len == std::string::npos) {
// error: port not found
std::cerr << "[" << ip_port << "] Missing port." << std::endl;
return opt_ip_port();
}
std::size_t port = std::strtoul(ip_port.substr(ip_len + 1).c_str(), NULL, 10);
if (port < 1 || port > 65535) {
// error: port out of range
std::cerr << "[" << ip_port << "] Port " << port << " out of range (1-65535)." << std::endl;
return opt_ip_port();
}
boost::system::error_code ec;
boost::asio::ip::address ip = boost::asio::ip::make_address(ip_port.substr(0, ip_len), ec);
if (ec) {
// error: IP-address invalid
std::cerr << "[" << ip_port << "] Invalid IP-address: " << ec.message() << std::endl;
return opt_ip_port();
}
return opt_ip_port({ip, port});
}
std::unique_ptr<LinkLayer>
create_link_layer(boost::asio::io_context& io_context, const EthernetDevice& device, const std::string& name, const boost::program_options::variables_map& vm)
{
std::unique_ptr<LinkLayer> link_layer;
if (name == "ethernet" || name == "cohda") {
boost::asio::generic::raw_protocol raw_protocol(AF_PACKET, vanetza::access::ethertype::GeoNetworking.net());
boost::asio::generic::raw_protocol::socket raw_socket(io_context, raw_protocol);
raw_socket.bind(device.endpoint(AF_PACKET));
if (name == "ethernet") {
link_layer.reset(new RawSocketLink { std::move(raw_socket) });
} else if (name == "cohda") {
#ifdef SOCKTAP_WITH_COHDA_LLC
link_layer.reset(new CohdaLink { std::move(raw_socket) });
#endif
}
} else if (name == "udp") {
namespace ip = boost::asio::ip;
ip::udp::endpoint multicast(ip::make_address("239.118.122.97"), 8947);
link_layer.reset(new UdpLink { io_context, multicast, device });
} else if (name == "tcp") {
namespace ip = boost::asio::ip;
TcpLink* tcp = new TcpLink { io_context };
if (vm.count("tcp-connect")) {
for (const std::string& ip_port : vm["tcp-connect"].as<std::vector<std::string>>()) {
auto ip_port_pair = parse_ip_port(ip_port);
if (ip_port_pair) {
tcp->connect(ip::tcp::endpoint(ip_port_pair.value().first, ip_port_pair.value().second));
}
}
}
if (vm.count("tcp-accept")) {
for (const std::string& ip_port : vm["tcp-accept"].as<std::vector<std::string>>()) {
auto ip_port_pair = parse_ip_port(ip_port);
if (ip_port_pair) {
tcp->accept(ip::tcp::endpoint(ip_port_pair.value().first, ip_port_pair.value().second));
}
}
}
link_layer.reset(tcp);
} else if (name == "autotalks") {
#ifdef SOCKTAP_WITH_AUTOTALKS
link_layer.reset(new AutotalksLink { io_context });
#endif
} else if (name == "cube-evk") {
#ifdef SOCKTAP_WITH_CUBE_EVK
link_layer.reset(new CubeEvkLink {
io_context,
boost::asio::ip::make_address(vm["cube-ip"].as<std::string>()),
vm["cube-tx-port"].as<unsigned>(),
vm["cube-rx-port"].as<unsigned>()
});
#endif
} else if (name == "rpc") {
#ifdef SOCKTAP_WITH_RPC
boost::asio::ip::tcp::socket socket(io_context);
boost::asio::ip::tcp::resolver resolver(io_context);
auto rpc_host = vm["rpc-host"].as<std::string>();
auto rpc_port = vm["rpc-port"].as<unsigned>();
auto endpoints = resolver.resolve(rpc_host, std::to_string(rpc_port));
boost::asio::connect(socket, endpoints);
link_layer.reset(new RpcLinkLayer {io_context, std::move(socket)});
if (auto rpc_link_layer = static_cast<RpcLinkLayer*>(link_layer.get())) {
rpc_link_layer->radio_technology(vm["rpc-radio-technology"].as<std::string>());
rpc_link_layer->enable_debug(vm["rpc-debug"].as<bool>());
}
#endif
}
return link_layer;
}
void add_link_layer_options(boost::program_options::options_description& options)
{
options.add_options()
("tcp-connect", boost::program_options::value<std::vector<std::string>>()->multitoken(), "Connect to TCP-Host(s). Comma separated list of [ip]:[port].")
("tcp-accept", boost::program_options::value<std::vector<std::string>>()->multitoken(), "Accept TCP-Connections. Comma separated list of [ip]:[port].")
;
}