Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
everest::run_application
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"iso15118_vas/ISO15118_vasImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# Check for radvd and udhcpd executables
|
||||
find_program(RADVD_EXECUTABLE radvd)
|
||||
if(NOT RADVD_EXECUTABLE)
|
||||
message(WARNING "radvd executable not found. The Iso15118InternetVas module will not work correctly.")
|
||||
endif()
|
||||
|
||||
find_program(UDHCPD_EXECUTABLE udhcpd)
|
||||
if(NOT UDHCPD_EXECUTABLE)
|
||||
message(WARNING "udhcpd executable not found. The Iso15118InternetVas module will not work correctly.")
|
||||
endif()
|
||||
|
||||
install(
|
||||
PROGRAMS
|
||||
vas-internet-setup.sh
|
||||
DESTINATION "${EVEREST_MODULE_INSTALL_PREFIX}/${MODULE_NAME}"
|
||||
)
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "Iso15118InternetVas.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void Iso15118InternetVas::init() {
|
||||
invoke_init(*p_iso15118_vas);
|
||||
}
|
||||
|
||||
void Iso15118InternetVas::ready() {
|
||||
invoke_ready(*p_iso15118_vas);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef ISO15118INTERNET_VAS_HPP
|
||||
#define ISO15118INTERNET_VAS_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/ISO15118_vas/Implementation.hpp>
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/evse_manager/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string ev_interface;
|
||||
std::string modem_interface;
|
||||
bool http_support;
|
||||
bool https_support;
|
||||
std::string vas_setup_script;
|
||||
};
|
||||
|
||||
class Iso15118InternetVas : public Everest::ModuleBase {
|
||||
public:
|
||||
Iso15118InternetVas() = delete;
|
||||
Iso15118InternetVas(const ModuleInfo& info, std::unique_ptr<ISO15118_vasImplBase> p_iso15118_vas,
|
||||
std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager, Conf& config) :
|
||||
ModuleBase(info),
|
||||
p_iso15118_vas(std::move(p_iso15118_vas)),
|
||||
r_evse_manager(std::move(r_evse_manager)),
|
||||
config(config){};
|
||||
|
||||
const std::unique_ptr<ISO15118_vasImplBase> p_iso15118_vas;
|
||||
const std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // ISO15118INTERNET_VAS_HPP
|
||||
@@ -0,0 +1,123 @@
|
||||
.. _everest_modules_handwritten_Iso15118InternetVas:
|
||||
|
||||
.. *******************************************
|
||||
.. Iso15118InternetVas
|
||||
.. *******************************************
|
||||
|
||||
.. warning::
|
||||
This module and its helper scripts are **examples** and not intended for
|
||||
production use without modification. The provided ``vas-internet-setup.sh``
|
||||
script is a starting point and may not cover all edge cases for your
|
||||
specific hardware and network environment. It is the user's responsibility
|
||||
to ensure the configuration is secure and robust.
|
||||
|
||||
This module implements the ISO 15118-2 Value Added Service (VAS) for providing
|
||||
internet access to a connected electric vehicle (EV). When an EV requests this
|
||||
service, the module configures the charger's networking to share its internet
|
||||
connection with the EV over the power line communication (PLC) interface.
|
||||
|
||||
How it works
|
||||
============
|
||||
|
||||
1. **Service Announcement**: The module advertises the availability of the
|
||||
Internet Access service (Service ID 3) to the EV, offering HTTP and/or HTTPS
|
||||
access based on the module's configuration.
|
||||
2. **Service Selection**: If the EV selects this service, the module initiates
|
||||
the network setup.
|
||||
3. **Network Setup**: The module executes a helper script,
|
||||
``vas-internet-setup.sh``, to configure all necessary networking components.
|
||||
The script's behavior depends on the configuration and the services selected
|
||||
by the EV:
|
||||
|
||||
- It enables IPv6 forwarding and sets up NAT using ``ip6tables``.
|
||||
- If IPv4 support is enabled in the configuration, it also:
|
||||
|
||||
- Starts a DHCPv4 server (``udhcpd``) on the EV-facing network
|
||||
interface (``ev_interface``). This DHCP server provides the EV with an
|
||||
IPv4 address and DNS server information.
|
||||
- Enables IPv4 forwarding and NAT using ``iptables``.
|
||||
|
||||
- It starts a Router Advertisement Daemon (``radvd``) on the
|
||||
``ev_interface`` to enable the EV to configure an IPv6 address using SLAAC.
|
||||
This also includes advertising Recursive DNS Servers (RDNSS) for IPv6.
|
||||
- The module determines which ports to open based on the parameter sets
|
||||
(HTTP, HTTPS) selected by the EV. The forwarding is then restricted to
|
||||
allow only TCP traffic on the selected ports (80 for HTTP, 443 for HTTPS).
|
||||
- The example script uses public DNS servers (Google's 8.8.8.8 for IPv4
|
||||
and 2001:4860:4860::8888 for IPv6). This can be changed in the script.
|
||||
4. **Session Teardown**: When the charging session ends (signaled by the
|
||||
``evse_manager``), the module calls the same script to automatically tear
|
||||
down the network configuration, stopping the services and removing all
|
||||
forwarding and NAT rules.
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
Software
|
||||
--------
|
||||
|
||||
The module relies on the ``vas-internet-setup.sh`` script, which requires the
|
||||
following external tools to be available in the system's PATH:
|
||||
|
||||
- ``radvd``: For IPv6 Router Advertisements.
|
||||
- ``ip6tables``: For setting up IPv6 NAT and forwarding rules.
|
||||
- ``ip`` (from the ``iproute2`` package): For network interface configuration.
|
||||
- ``iptables`` (optional, for IPv4): For IPv4 NAT and forwarding rules.
|
||||
- ``udhcpd`` (optional, for IPv4): For the DHCPv4 server (typically provided by
|
||||
BusyBox).
|
||||
|
||||
The EVerest framework must be run with sufficient privileges to allow these
|
||||
tools to modify network settings. This typically means running as the ``root``
|
||||
user.
|
||||
|
||||
Hardware
|
||||
--------
|
||||
|
||||
- A working internet connection on the charging station.
|
||||
- A network interface that is connected to the internet (e.g., ``eth0``, ``wwan0``).
|
||||
- A network interface for the Power Line Communication (PLC) modem that
|
||||
communicates with the EV (e.g., a HomePlug Green PHY modem connected via
|
||||
Ethernet).
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
.. list-table::
|
||||
:widths: 25 75
|
||||
:header-rows: 1
|
||||
|
||||
* - Key
|
||||
- Description
|
||||
* - ``ev_interface``
|
||||
- The name of the network interface connected to the EV via the PLC modem.
|
||||
* - ``modem_interface``
|
||||
- The name of the network interface connected to the internet.
|
||||
* - ``http_support``
|
||||
- (boolean) Whether to announce support for HTTP (Port 80). Defaults to `true`.
|
||||
* - ``https_support``
|
||||
- (boolean) Whether to announce support for HTTPS (Port 443). Defaults to `true`.
|
||||
|
||||
Example Configuration
|
||||
---------------------
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- module: Iso15118InternetVas
|
||||
config:
|
||||
ev_interface: eth1
|
||||
modem_interface: eth0
|
||||
http_support: true
|
||||
https_support: true
|
||||
|
||||
Provided Interfaces
|
||||
===================
|
||||
|
||||
- **iso15118_vas**: Implements the ``ISO15118_vas`` interface to handle service
|
||||
discovery and selection from the EV.
|
||||
|
||||
Required Interfaces
|
||||
===================
|
||||
|
||||
- **evse_manager**: The module optionally connects to an ``evse_manager`` to
|
||||
monitor the charging session. When the session finishes, it triggers the
|
||||
teardown of the internet connection for the EV.
|
||||
@@ -0,0 +1,187 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <algorithm>
|
||||
#include <everest/run_application/run_application.hpp>
|
||||
#include <generated/types/iso15118_vas.hpp>
|
||||
|
||||
#include "ISO15118_vasImpl.hpp"
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace module {
|
||||
namespace iso15118_vas {
|
||||
|
||||
constexpr int32_t InternetAccessServiceIdD2 = 3;
|
||||
constexpr int HTTP_PARAM_SET_ID = 3;
|
||||
constexpr int HTTPS_PARAM_SET_ID = 4;
|
||||
constexpr int HTTP_PORT = 80;
|
||||
constexpr int HTTPS_PORT = 443;
|
||||
const std::string PARAM_NAME_PROTOCOL = "Protocol";
|
||||
const std::string PARAM_NAME_PORT = "Port";
|
||||
const std::string VALUE_HTTP = "http";
|
||||
const std::string VALUE_HTTPS = "https";
|
||||
|
||||
ISO15118_vasImpl::~ISO15118_vasImpl() {
|
||||
this->stop_internet_service();
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::init() {
|
||||
if (!this->mod->r_evse_manager.empty()) {
|
||||
this->mod->r_evse_manager.at(0)->subscribe_session_event(
|
||||
[this](types::evse_manager::SessionEvent session_event) {
|
||||
if (session_event.event == types::evse_manager::SessionEventEnum::SessionFinished and
|
||||
this->internet_service_running) {
|
||||
this->stop_internet_service();
|
||||
}
|
||||
});
|
||||
}
|
||||
const auto config_setup_script = fs::path(this->mod->config.vas_setup_script);
|
||||
if (config_setup_script.is_relative()) {
|
||||
this->internet_setup_script = (this->mod->info.paths.libexec / this->mod->config.vas_setup_script).string();
|
||||
} else {
|
||||
this->internet_setup_script = this->mod->config.vas_setup_script;
|
||||
}
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::ready() {
|
||||
this->publish_offered_vas({{{InternetAccessServiceIdD2}}});
|
||||
}
|
||||
|
||||
std::vector<types::iso15118_vas::ParameterSet> ISO15118_vasImpl::handle_get_service_parameters(int& service_id) {
|
||||
std::vector<types::iso15118_vas::ParameterSet> ret{};
|
||||
if (service_id == InternetAccessServiceIdD2) {
|
||||
ret.reserve(2);
|
||||
|
||||
if (this->mod->config.http_support) {
|
||||
// HTTP
|
||||
types::iso15118_vas::ParameterSet http_params;
|
||||
http_params.set_id = HTTP_PARAM_SET_ID;
|
||||
http_params.parameters.reserve(2);
|
||||
|
||||
types::iso15118_vas::Parameter http_param;
|
||||
http_param.name = PARAM_NAME_PROTOCOL;
|
||||
types::iso15118_vas::ParameterValue http_protocol_name;
|
||||
http_protocol_name.finite_string = VALUE_HTTP;
|
||||
http_param.value = http_protocol_name;
|
||||
|
||||
types::iso15118_vas::Parameter http_port;
|
||||
http_port.name = PARAM_NAME_PORT;
|
||||
types::iso15118_vas::ParameterValue http_port_value;
|
||||
http_port_value.int_value = HTTP_PORT;
|
||||
http_port.value = http_port_value;
|
||||
http_params.parameters.emplace_back(http_param);
|
||||
http_params.parameters.emplace_back(http_port);
|
||||
|
||||
ret.emplace_back(http_params);
|
||||
}
|
||||
|
||||
if (this->mod->config.https_support) {
|
||||
// HTTPS
|
||||
types::iso15118_vas::ParameterSet https_params;
|
||||
https_params.set_id = HTTPS_PARAM_SET_ID;
|
||||
https_params.parameters.reserve(2);
|
||||
|
||||
types::iso15118_vas::Parameter https_param;
|
||||
https_param.name = PARAM_NAME_PROTOCOL;
|
||||
types::iso15118_vas::ParameterValue https_protocol_name;
|
||||
https_protocol_name.finite_string = VALUE_HTTPS;
|
||||
https_param.value = https_protocol_name;
|
||||
|
||||
types::iso15118_vas::Parameter https_port;
|
||||
https_port.name = PARAM_NAME_PORT;
|
||||
types::iso15118_vas::ParameterValue https_port_value;
|
||||
https_port_value.int_value = HTTPS_PORT;
|
||||
https_port.value = https_port_value;
|
||||
https_params.parameters.emplace_back(https_param);
|
||||
https_params.parameters.emplace_back(https_port);
|
||||
|
||||
ret.emplace_back(https_params);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<int> ISO15118_vasImpl::get_selected_internet_ports(
|
||||
const std::vector<types::iso15118_vas::SelectedService>& selected_services) {
|
||||
std::vector<int> selected_ports;
|
||||
|
||||
for (const auto& service : selected_services) {
|
||||
if (service.service_id == InternetAccessServiceIdD2) {
|
||||
if (this->mod->config.http_support and service.parameter_set_id == HTTP_PARAM_SET_ID) {
|
||||
if (std::find(selected_ports.begin(), selected_ports.end(), HTTP_PORT) == selected_ports.end()) {
|
||||
selected_ports.push_back(HTTP_PORT);
|
||||
}
|
||||
} else if (this->mod->config.https_support and service.parameter_set_id == HTTPS_PARAM_SET_ID) {
|
||||
if (std::find(selected_ports.begin(), selected_ports.end(), HTTPS_PORT) == selected_ports.end()) {
|
||||
selected_ports.push_back(HTTPS_PORT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selected_ports;
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::handle_selected_services(std::vector<types::iso15118_vas::SelectedService>& selected_services) {
|
||||
const auto ports_to_open = this->get_selected_internet_ports(selected_services);
|
||||
|
||||
if (!ports_to_open.empty()) {
|
||||
std::string ports_str;
|
||||
for (size_t i = 0; i < ports_to_open.size(); ++i) {
|
||||
ports_str += std::to_string(ports_to_open[i]);
|
||||
if (i < ports_to_open.size() - 1) {
|
||||
ports_str += ",";
|
||||
}
|
||||
}
|
||||
start_internet_service(ports_str);
|
||||
}
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::start_script(const std::string& script_name, const std::vector<std::string>& args) {
|
||||
auto output = everest::run_application::run_application(script_name, args);
|
||||
if (output.exit_code != 0) {
|
||||
EVLOG_warning << "Script: " << script_name << " exited with code: " << output.exit_code;
|
||||
EVLOG_warning << "Script output:";
|
||||
EVLOG_warning << output.output;
|
||||
}
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::start_internet_service(const std::string& ports) {
|
||||
{
|
||||
std::lock_guard lock(internet_mutex);
|
||||
if (this->internet_service_running) {
|
||||
EVLOG_warning << "Internet service is already running.";
|
||||
return;
|
||||
}
|
||||
this->internet_service_running = true;
|
||||
}
|
||||
this->active_ports = ports;
|
||||
EVLOG_info << "Starting internet service for ports: " << this->active_ports;
|
||||
|
||||
std::thread(&ISO15118_vasImpl::start_script, this, this->internet_setup_script,
|
||||
std::vector<std::string>{"up", this->mod->config.ev_interface, this->mod->config.modem_interface,
|
||||
this->active_ports})
|
||||
.detach();
|
||||
}
|
||||
|
||||
void ISO15118_vasImpl::stop_internet_service() {
|
||||
{
|
||||
std::lock_guard lock(internet_mutex);
|
||||
if (!this->internet_service_running) {
|
||||
EVLOG_warning << "Internet service is not running.";
|
||||
return;
|
||||
}
|
||||
this->internet_service_running = false;
|
||||
}
|
||||
EVLOG_info << "Stopping internet service for ports: " << this->active_ports;
|
||||
|
||||
std::thread(&ISO15118_vasImpl::start_script, this, this->internet_setup_script,
|
||||
std::vector<std::string>{"down", this->mod->config.ev_interface, this->mod->config.modem_interface,
|
||||
this->active_ports})
|
||||
.detach();
|
||||
this->active_ports.clear();
|
||||
}
|
||||
|
||||
} // namespace iso15118_vas
|
||||
} // namespace module
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef ISO15118_VAS_ISO15118_VAS_IMPL_HPP
|
||||
#define ISO15118_VAS_ISO15118_VAS_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ISO15118_vas/Implementation.hpp>
|
||||
|
||||
#include "../Iso15118InternetVas.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
#include <mutex>
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace iso15118_vas {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ISO15118_vasImpl : public ISO15118_vasImplBase {
|
||||
public:
|
||||
ISO15118_vasImpl() = delete;
|
||||
ISO15118_vasImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Iso15118InternetVas>& mod, Conf& config) :
|
||||
ISO15118_vasImplBase(ev, "iso15118_vas"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
~ISO15118_vasImpl() override;
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual std::vector<types::iso15118_vas::ParameterSet> handle_get_service_parameters(int& service_id) override;
|
||||
virtual void
|
||||
handle_selected_services(std::vector<types::iso15118_vas::SelectedService>& selected_services) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<Iso15118InternetVas>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
void start_script(const std::string& script_name, const std::vector<std::string>& args);
|
||||
void start_internet_service(const std::string& ports);
|
||||
void stop_internet_service();
|
||||
std::vector<int>
|
||||
get_selected_internet_ports(const std::vector<types::iso15118_vas::SelectedService>& selected_services);
|
||||
|
||||
std::string internet_setup_script = "";
|
||||
bool internet_service_running{false};
|
||||
std::mutex internet_mutex;
|
||||
std::string active_ports;
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace iso15118_vas
|
||||
} // namespace module
|
||||
|
||||
#endif // ISO15118_VAS_ISO15118_VAS_IMPL_HPP
|
||||
@@ -0,0 +1,41 @@
|
||||
description: >-
|
||||
This module provides ISO15118 internet value-added services (VAS).
|
||||
config:
|
||||
ev_interface:
|
||||
description: >-
|
||||
Name of the interface which is connected to the EV.
|
||||
type: string
|
||||
modem_interface:
|
||||
description: >-
|
||||
Name of the interface which is connected to the internet.
|
||||
type: string
|
||||
http_support:
|
||||
description: >-
|
||||
Boolean dictating whether we should let the EV know we support HTTP
|
||||
type: boolean
|
||||
https_support:
|
||||
description: >-
|
||||
Boolean dictating whether we should let the EV know we support HTTPS
|
||||
type: boolean
|
||||
vas_setup_script:
|
||||
description: >-
|
||||
Filepath of the script, which is executed to setup the VaS network.
|
||||
A relative filepath is appended to the module directory:
|
||||
/usr/libexec/everest/modules/Iso15118InternetVas/.
|
||||
That means in the default case, it expands to: /usr/libexec/everest/modules/Iso15118InternetVas/vas-internet-setup.sh.
|
||||
An absolute filepath is directly executed.
|
||||
type: string
|
||||
default: "vas-internet-setup.sh"
|
||||
provides:
|
||||
iso15118_vas:
|
||||
interface: ISO15118_vas
|
||||
description: The internet VAS
|
||||
requires:
|
||||
evse_manager:
|
||||
interface: evse_manager
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Martin Litre, Pionix GmbH
|
||||
283
tools/EVerest-main/modules/EVSE/Iso15118InternetVas/vas-internet-setup.sh
Executable file
283
tools/EVerest-main/modules/EVSE/Iso15118InternetVas/vas-internet-setup.sh
Executable file
@@ -0,0 +1,283 @@
|
||||
#!/bin/sh
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
#
|
||||
# WARNING: This script is an example and not intended for production use.
|
||||
#
|
||||
# This script is provided as a starting point for setting up internet
|
||||
# access for an EV. It is not a complete solution and may require
|
||||
# modification to work in your specific environment.
|
||||
#
|
||||
# It is the responsibility of the user to ensure that the script is
|
||||
# secure and does not introduce any security vulnerabilities.
|
||||
#
|
||||
# --------------------------------------------------------------------------
|
||||
|
||||
# This script manages the full network setup to provide internet access
|
||||
# to an EV. It handles IP forwarding, NAT, a DHCP server, and a
|
||||
# router advertisement daemon.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Configuration ---
|
||||
DHCP_STATIC_IP="172.18.200.1"
|
||||
SUBNET_MASK="24"
|
||||
RADVD_IPV6_PREFIX="fd00::/64"
|
||||
|
||||
# --- File Paths ---
|
||||
PID_DIR="/var/run"
|
||||
DHCP_PID_FILE="${PID_DIR}/vas_udhcpd.pid"
|
||||
RADVD_PID_FILE="${PID_DIR}/vas_radvd.pid"
|
||||
|
||||
CONF_DIR="/tmp"
|
||||
DHCP_CONF_FILE="${CONF_DIR}/vas_udhcpd.conf"
|
||||
RADVD_CONF_FILE="${CONF_DIR}/vas_radvd.conf"
|
||||
|
||||
# Load optional configuration from /etc/default/vas-internet
|
||||
[ -f /etc/default/vas-internet ] && . /etc/default/vas-internet
|
||||
|
||||
# --- Helper Functions ---
|
||||
need_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "Please run as root (use sudo)." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_deps() {
|
||||
local use_ipv4=$1
|
||||
local deps="ip ip6tables radvd"
|
||||
if [ "$use_ipv4" = true ]; then
|
||||
deps="$deps iptables udhcpd"
|
||||
fi
|
||||
|
||||
for cmd in $deps; do
|
||||
if ! cmd_exists "$cmd"; then
|
||||
echo "Error: Command '$cmd' not found. Please install it." >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# --- Core Logic Functions ---
|
||||
|
||||
start_services() {
|
||||
local LAN_IFACE=$1
|
||||
local WAN_IFACE=$2
|
||||
local PORTS=${3:-}
|
||||
local USE_IPV4=$4
|
||||
|
||||
echo "[+] Starting all internet VAS services for $LAN_IFACE -> $WAN_IFACE"
|
||||
|
||||
# 1. Enable IP Forwarding
|
||||
echo " [1/4] Enabling IP forwarding"
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
sysctl -w net.ipv4.ip_forward=1 >/dev/null
|
||||
fi
|
||||
sysctl -w net.ipv6.conf.all.forwarding=1 >/dev/null
|
||||
|
||||
# 2. Setup NAT and Forwarding Rules
|
||||
echo " [2/4] Setting up NAT and FORWARD rules on $WAN_IFACE"
|
||||
|
||||
# Create custom chains
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -N VAS_FORWARD 2>/dev/null || iptables -F VAS_FORWARD
|
||||
fi
|
||||
ip6tables -N VAS_FORWARD 2>/dev/null || ip6tables -F VAS_FORWARD
|
||||
|
||||
# Jump to custom chain
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -C FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD 2>/dev/null || \
|
||||
iptables -A FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD
|
||||
fi
|
||||
ip6tables -C FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD 2>/dev/null || \
|
||||
ip6tables -A FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD
|
||||
|
||||
# MASQUERADE rule for outbound traffic on WAN interface
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -t nat -C POSTROUTING -o "$WAN_IFACE" -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -o "$WAN_IFACE" -j MASQUERADE
|
||||
fi
|
||||
ip6tables -t nat -C POSTROUTING -o "$WAN_IFACE" -j MASQUERADE 2>/dev/null || \
|
||||
ip6tables -t nat -A POSTROUTING -o "$WAN_IFACE" -j MASQUERADE
|
||||
|
||||
# Allow return traffic for established connections
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -C FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||
iptables -A FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
fi
|
||||
ip6tables -C FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
|
||||
ip6tables -A FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
|
||||
# Add specific forwarding rules for outbound traffic from LAN interface
|
||||
echo " - Allowing outgoing traffic on TCP ports: $PORTS"
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
# TCP
|
||||
iptables -A VAS_FORWARD -p tcp -m multiport --dports "$PORTS" -j ACCEPT
|
||||
fi
|
||||
|
||||
# TCP (IPv6)
|
||||
ip6tables -A VAS_FORWARD -p tcp -m multiport --dports "$PORTS" -j ACCEPT
|
||||
|
||||
# 3. Start DHCP server
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
echo " [3/4] Starting DHCPv4 server on $LAN_IFACE"
|
||||
local IP_WITH_SUBNET="${DHCP_STATIC_IP}/${SUBNET_MASK}"
|
||||
ip addr show dev "${LAN_IFACE}" | grep -q "${IP_WITH_SUBNET}" || ip addr add "${IP_WITH_SUBNET}" dev "${LAN_IFACE}"
|
||||
|
||||
local NETWORK_BASE=$(echo "$DHCP_STATIC_IP" | cut -d. -f1-3)
|
||||
cat > "${DHCP_CONF_FILE}" << EOF
|
||||
interface ${LAN_IFACE}
|
||||
start ${NETWORK_BASE}.2
|
||||
end ${NETWORK_BASE}.200
|
||||
option subnet 255.255.255.0
|
||||
option router ${DHCP_STATIC_IP}
|
||||
option dns 8.8.8.8 8.8.4.4
|
||||
option lease 864000
|
||||
pidfile ${DHCP_PID_FILE}
|
||||
EOF
|
||||
udhcpd -S "${DHCP_CONF_FILE}"
|
||||
else
|
||||
echo " [3/4] Skipping DHCPv4 server (IPv4 disabled)"
|
||||
fi
|
||||
|
||||
# 4. Start RADVD server
|
||||
echo " [4/4] Starting DHCPv6/RADVD server on $LAN_IFACE"
|
||||
cat > "${RADVD_CONF_FILE}" << EOF
|
||||
interface ${LAN_IFACE}
|
||||
{
|
||||
AdvSendAdvert on;
|
||||
MinRtrAdvInterval 30;
|
||||
MaxRtrAdvInterval 100;
|
||||
prefix ${RADVD_IPV6_PREFIX}
|
||||
{
|
||||
AdvOnLink on;
|
||||
AdvAutonomous on;
|
||||
AdvRouterAddr off;
|
||||
};
|
||||
RDNSS 2001:4860:4860::8888 2001:4860:4860::8844
|
||||
{
|
||||
AdvRDNSSLifetime 3600;
|
||||
};
|
||||
};
|
||||
EOF
|
||||
radvd -C "${RADVD_CONF_FILE}" -p "${RADVD_PID_FILE}"
|
||||
|
||||
echo "[✓] All services started."
|
||||
}
|
||||
|
||||
stop_services() {
|
||||
local LAN_IFACE=$1
|
||||
local WAN_IFACE=$2
|
||||
local PORTS=$3
|
||||
local USE_IPV4=$4
|
||||
|
||||
echo "[+] Stopping all internet VAS services for $LAN_IFACE -> $WAN_IFACE"
|
||||
|
||||
# 1. Stop daemons
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
echo " [1/3] Stopping DHCPv4 server"
|
||||
if [ -f "$DHCP_PID_FILE" ]; then
|
||||
kill "$(cat "$DHCP_PID_FILE")" || echo "DHCP server already stopped."
|
||||
rm -f "$DHCP_PID_FILE"
|
||||
else
|
||||
echo "DHCP PID file not found. Maybe it was not running."
|
||||
fi
|
||||
fi
|
||||
|
||||
echo " [2/3] Stopping DHCPv6/RADVD server"
|
||||
if [ -f "$RADVD_PID_FILE" ]; then
|
||||
kill "$(cat "$RADVD_PID_FILE")" || echo "RADVD server already stopped."
|
||||
rm -f "$RADVD_PID_FILE"
|
||||
else
|
||||
echo "RADVD PID file not found. Maybe it was not running."
|
||||
fi
|
||||
|
||||
# 2. Remove NAT and FORWARD rules
|
||||
echo " [3/3] Removing NAT and FORWARD rules"
|
||||
|
||||
# Remove jump rule
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -D FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD 2>/dev/null || true
|
||||
fi
|
||||
ip6tables -D FORWARD -i "$LAN_IFACE" -o "$WAN_IFACE" -j VAS_FORWARD 2>/dev/null || true
|
||||
|
||||
# Flush and delete custom chain
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -F VAS_FORWARD 2>/dev/null || true
|
||||
iptables -X VAS_FORWARD 2>/dev/null || true
|
||||
fi
|
||||
ip6tables -F VAS_FORWARD 2>/dev/null || true
|
||||
ip6tables -X VAS_FORWARD 2>/dev/null || true
|
||||
|
||||
if [ "$USE_IPV4" = true ]; then
|
||||
iptables -t nat -D POSTROUTING -o "$WAN_IFACE" -j MASQUERADE 2>/dev/null || true
|
||||
iptables -D FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||
fi
|
||||
ip6tables -t nat -D POSTROUTING -o "$WAN_IFACE" -j MASQUERADE 2>/dev/null || true
|
||||
ip6tables -D FORWARD -i "$WAN_IFACE" -o "$LAN_IFACE" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
|
||||
|
||||
echo "[✓] All services stopped and rules removed."
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage:
|
||||
sudo $0 up <LAN_IFACE> <WAN_IFACE> <PORTS> [--ipv4]
|
||||
sudo $0 down <LAN_IFACE> <WAN_IFACE> <PORTS> [--ipv4]
|
||||
|
||||
Commands:
|
||||
up - Configures interfaces, enables NAT/forwarding, and starts DHCP/RADVD.
|
||||
down - Stops daemons and removes all created network rules.
|
||||
|
||||
Arguments:
|
||||
PORTS - Comma-separated list of TCP ports to allow (e.g., "80,443").
|
||||
--ipv4 - Optional flag to enable all IPv4-related setup (disabled by default).
|
||||
EOF
|
||||
}
|
||||
|
||||
main() {
|
||||
need_root
|
||||
|
||||
local use_ipv4=false
|
||||
local args=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--ipv4)
|
||||
use_ipv4=true
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
args+=("$1")
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
check_deps "$use_ipv4"
|
||||
|
||||
local cmd="${args[0]:-}"
|
||||
if [[ ${#args[@]} -ne 4 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$cmd" in
|
||||
up)
|
||||
start_services "${args[1]}" "${args[2]}" "${args[3]}" "$use_ipv4"
|
||||
;;
|
||||
down)
|
||||
stop_services "${args[1]}" "${args[2]}" "${args[3]}" "$use_ipv4"
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user