Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/pnc related #44

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/iso15118/io/sdp_packet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ class SdpPacket {
void parse_header();

State state{State::EMPTY};
uint8_t buffer[2048];
// FIXME (aw): what buffer size to allow here? Could also be made
// dynamic
uint8_t buffer[4096];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should start to use std::array instead of a c buffer.
I am fine with increasing the buffer size to 4096. I think that's more of an experience value. 4096 should be enough for now.

size_t bytes_read{0};
size_t length; // length includes V2GTP_HEADER_SIZE
};
Expand Down
12 changes: 4 additions & 8 deletions include/iso15118/message/authorization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Copyright 2023 Pionix GmbH and Contributors to EVerest
#pragma once

#include <optional>
#include <string>
#include <variant>
#include <vector>

#include "common.hpp"
Expand All @@ -20,11 +20,8 @@

// Todo(sl): Refactor in common
struct ContractCertificateChain {
struct Certificate {
std::vector<uint8_t> certificate;
};
Certificate certificate;
std::vector<Certificate> sub_certificates;
std::vector<uint8_t> certificate;
std::vector<std::vector<uint8_t>> sub_certificates;

Check notice on line 24 in include/iso15118/message/authorization.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/iso15118/message/authorization.hpp#L24

struct member 'ContractCertificateChain::sub_certificates' is never used.
};

struct EIM_ASReqAuthorizationMode {};
Expand All @@ -36,8 +33,7 @@

Header header;
Authorization selected_authorization_service;
std::optional<EIM_ASReqAuthorizationMode> eim_as_req_authorization_mode;
std::optional<PnC_ASReqAuthorizationMode> pnc_as_req_authorization_mode;
std::variant<EIM_ASReqAuthorizationMode, PnC_ASReqAuthorizationMode> authorization_mode;
};

struct AuthorizationResponse {
Expand Down
1 change: 1 addition & 0 deletions include/iso15118/session/feedback.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace feedback {

enum class Signal {
REQUIRE_AUTH_EIM,
REQUIRE_AUTH_PNC,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we should send also the contract cert chain from the AuthorizationReq message as well. But only once.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not have to be part of this PR, but will be added when PnC is fully implemented.

START_CABLE_CHECK,
SETUP_FINISHED,
CHARGE_LOOP_STARTED,
Expand Down
45 changes: 17 additions & 28 deletions src/iso15118/d20/state/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,24 @@ message_20::AuthorizationResponse handle_request(const message_20::Authorization

auto response_code = message_20::ResponseCode::OK;

switch (req.selected_authorization_service) {
case message_20::Authorization::EIM:
switch (authorization_status) {
case AuthStatus::Accepted:
res.evse_processing = message_20::Processing::Finished;
response_code = message_20::ResponseCode::OK;
break;
case AuthStatus::Rejected: // Failure [V2G20-2230]
res.evse_processing = message_20::Processing::Finished;
response_code = message_20::ResponseCode::WARNING_EIMAuthorizationFailure;
break;
case AuthStatus::Pending:
default:
res.evse_processing = message_20::Processing::Ongoing;
response_code = message_20::ResponseCode::OK;
break;
}
const auto get_rejection_response_code = [](message_20::Authorization auth_method) {
return (auth_method == message_20::Authorization::EIM)
? message_20::ResponseCode::WARNING_EIMAuthorizationFailure
: message_20::ResponseCode::WARNING_GeneralPnCAuthorizationError;
};

switch (authorization_status) {
case AuthStatus::Accepted:
res.evse_processing = message_20::Processing::Finished;
response_code = message_20::ResponseCode::OK;
break;

case message_20::Authorization::PnC:
// todo(SL): Handle PnC
case AuthStatus::Rejected: // Failure [V2G20-2230]
res.evse_processing = message_20::Processing::Finished;
response_code = get_rejection_response_code(req.selected_authorization_service);
break;

default:
// todo(SL): Fill
case AuthStatus::Pending:
res.evse_processing = message_20::Processing::Ongoing;
response_code = message_20::ResponseCode::OK;
break;
}

Expand All @@ -82,11 +75,7 @@ FsmSimpleState::HandleEventReturnType Authorization::handle_event(AllocatorType&
return sa.HANDLED_INTERNALLY;
}

if (*control_data) {
authorization_status = AuthStatus::Accepted;
} else {
authorization_status = AuthStatus::Rejected;
}
authorization_status = (*control_data) ? AuthStatus::Accepted : AuthStatus::Rejected;

return sa.HANDLED_INTERNALLY;
}
Expand Down
14 changes: 12 additions & 2 deletions src/iso15118/d20/state/authorization_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@

namespace iso15118::d20::state {

namespace {
auto required_auth_signal(const message_20::AuthorizationSetupResponse& res) {
using Signal = session::feedback::Signal;
return (std::holds_alternative<message_20::AuthorizationSetupResponse::PnC_ASResAuthorizationMode>(
res.authorization_mode))
? Signal::REQUIRE_AUTH_PNC
: Signal::REQUIRE_AUTH_EIM;
}
} // namespace

message_20::AuthorizationSetupResponse
handle_request(const message_20::AuthorizationSetupRequest& req, d20::Session& session, bool cert_install_service,
const std::vector<message_20::Authorization>& authorization_services) {
Expand Down Expand Up @@ -40,6 +50,7 @@ handle_request(const message_20::AuthorizationSetupRequest& req, d20::Session& s
auto& pnc_auth_mode =
res.authorization_mode.emplace<message_20::AuthorizationSetupResponse::PnC_ASResAuthorizationMode>();

// FIXME (aw): refactor to utilities
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<uint8_t> distribution(0x00, 0xff);
Expand Down Expand Up @@ -77,8 +88,7 @@ FsmSimpleState::HandleEventReturnType AuthorizationSetup::handle_event(Allocator
return sa.PASS_ON;
}

// Todo(sl): PnC is currently not supported
ctx.feedback.signal(session::feedback::Signal::REQUIRE_AUTH_EIM);
ctx.feedback.signal(required_auth_signal(res));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should move this feedback.signal call to the authorization state. Only in the authorization state is it clear whether the car is requesting PnC or EIM.


return sa.create_simple<Authorization>(ctx);
} else if (const auto req = variant->get_if<message_20::SessionStopRequest>()) {
Expand Down
37 changes: 6 additions & 31 deletions src/iso15118/d20/state/dc_charge_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,18 @@ using Dynamic_BPT_DC_Res = message_20::DC_ChargeLoopResponse::BPT_Dynamic_DC_CLR

template <typename In, typename Out> void convert(Out& out, const In& in);

template <> void convert(Scheduled_DC_Res& out, const d20::DcTransferLimits& in) {
template <typename Out> void convert(Out& out, const d20::DcTransferLimits& in) {
out.max_charge_power = in.charge_limits.power.max;
out.min_charge_power = in.charge_limits.power.min;
out.max_charge_current = in.charge_limits.current.max;
out.max_voltage = in.voltage.max;
}

template <> void convert(Scheduled_BPT_DC_Res& out, const d20::DcTransferLimits& in) {
out.max_charge_power = in.charge_limits.power.max;
out.min_charge_power = in.charge_limits.power.min;
out.max_charge_current = in.charge_limits.current.max;
out.max_voltage = in.voltage.max;
out.min_voltage = in.voltage.min;

if (in.discharge_limits.has_value()) {
auto& discharge_limits = in.discharge_limits.value();
out.max_discharge_power = discharge_limits.power.max;
out.min_discharge_power = discharge_limits.power.min;
out.max_discharge_current = discharge_limits.current.max;
}
}

template <> void convert(Dynamic_DC_Res& out, const d20::DcTransferLimits& in) {
out.max_charge_power = in.charge_limits.power.max;
out.min_charge_power = in.charge_limits.power.min;
out.max_charge_current = in.charge_limits.current.max;
out.max_voltage = in.voltage.max;
}

template <> void convert(Dynamic_BPT_DC_Res& out, const d20::DcTransferLimits& in) {
out.max_charge_power = in.charge_limits.power.max;
out.min_charge_power = in.charge_limits.power.min;
out.max_charge_current = in.charge_limits.current.max;
out.max_voltage = in.voltage.max;
out.min_voltage = in.voltage.min;
if constexpr (std::is_same_v<Out, Scheduled_BPT_DC_Res> || std::is_same_v<Out, Dynamic_BPT_DC_Res>) {
out.min_voltage = in.voltage.min;

if (in.discharge_limits.has_value()) {
if (not in.discharge_limits) {
return;
}
auto& discharge_limits = in.discharge_limits.value();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto instead of auto

out.max_discharge_power = discharge_limits.power.max;
out.min_discharge_power = discharge_limits.power.min;
Expand Down
4 changes: 4 additions & 0 deletions src/iso15118/io/connection_openssl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ static SSL_CTX* init_ssl(const config::SSLConfig& ssl_config) {
log_and_raise_openssl_error("Failed in SSL_CTX_new()");
}

// NOTE (aw): this could also be set to TLS1_3_VERSION in order to
// enforce TLS1.3
if (SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION) == 0) {
log_and_raise_openssl_error("Failed in SSL_CTX_set_min_proto_version()");
}
Expand Down Expand Up @@ -289,6 +291,8 @@ void ConnectionSSL::handle_data() {
if ((ssl_error == SSL_ERROR_WANT_READ) or (ssl_error == SSL_ERROR_WANT_WRITE)) {
return;
}

// FIXME (aw): need to handle this gracefully
log_and_raise_openssl_error("Failed to SSL_accept(): " + std::to_string(ssl_error));
} else {
logf_info("Handshake complete!");
Expand Down
35 changes: 25 additions & 10 deletions src/iso15118/message/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,37 @@

namespace iso15118::message_20 {

// FIXME (aw): this template should be commonly reused
template <typename T, typename SourceType> void copy_bytes_to_vector(std::vector<T>& out, const SourceType& in) {
static_assert(std::is_same_v<T, std::remove_all_extents_t<decltype(in.bytes)>>);
out.reserve(in.bytesLen);
std::copy(in.bytes, in.bytes + in.bytesLen, std::back_inserter(out));
}

template <>
void convert(const struct iso20_PnC_AReqAuthorizationModeType& in,
AuthorizationRequest::PnC_ASReqAuthorizationMode& out) {
out.id = CB2CPP_STRING(in.Id);

copy_bytes_to_vector(out.gen_challenge, in.GenChallenge);
copy_bytes_to_vector(out.contract_certificate_chain.certificate, in.ContractCertificateChain.Certificate);

for (std::size_t i = 0; i < in.ContractCertificateChain.SubCertificates.Certificate.arrayLen; ++i) {
const auto& sub_certificate_in = in.ContractCertificateChain.SubCertificates.Certificate.array[i];
auto& sub_certificate_out = out.contract_certificate_chain.sub_certificates.emplace_back();
copy_bytes_to_vector(sub_certificate_out, sub_certificate_in);
}
}

template <> void convert(const struct iso20_AuthorizationReqType& in, AuthorizationRequest& out) {
convert(in.Header, out.header);

out.selected_authorization_service = static_cast<Authorization>(in.SelectedAuthorizationService);
if (in.EIM_AReqAuthorizationMode_isUsed) {
out.eim_as_req_authorization_mode.emplace();
out.authorization_mode = AuthorizationRequest::EIM_ASReqAuthorizationMode{};
} else if (in.PnC_AReqAuthorizationMode_isUsed) {

auto& pnc_out = out.pnc_as_req_authorization_mode.emplace();

pnc_out.id = CB2CPP_STRING(in.PnC_AReqAuthorizationMode.Id);
pnc_out.gen_challenge.reserve(in.PnC_AReqAuthorizationMode.GenChallenge.bytesLen);
pnc_out.gen_challenge.insert(
pnc_out.gen_challenge.end(), &in.PnC_AReqAuthorizationMode.GenChallenge.bytes[0],
&in.PnC_AReqAuthorizationMode.GenChallenge.bytes[in.PnC_AReqAuthorizationMode.GenChallenge.bytesLen]);
// Todo(sl): Adding certificate
auto& pnc_out = out.authorization_mode.emplace<AuthorizationRequest::PnC_ASReqAuthorizationMode>();
convert(in.PnC_AReqAuthorizationMode, pnc_out);
}
}

Expand Down
14 changes: 9 additions & 5 deletions src/iso15118/message/service_detail.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,20 @@ template <> void convert(const ServiceDetailResponse& in, iso20_ServiceDetailRes

uint8_t index = 0;
for (auto const& in_parameter_set : in.service_parameter_list) {
auto& out_paramater_set = out.ServiceParameterList.ParameterSet.array[index++];
out_paramater_set.ParameterSetID = in_parameter_set.id;
auto& out_parameter_set = out.ServiceParameterList.ParameterSet.array[index++];
init_iso20_ParameterSetType(&out_parameter_set);

out_parameter_set.ParameterSetID = in_parameter_set.id;

uint8_t t = 0;
for (auto const& in_parameter : in_parameter_set.parameter) {
auto& out_parameter = out_paramater_set.Parameter.array[t++];
auto& out_parameter = out_parameter_set.Parameter.array[t++];
init_iso20_ParameterType(&out_parameter);

CPP2CB_STRING(in_parameter.name, out_parameter.Name);
std::visit(ParamterValueVisitor(out_parameter), in_parameter.value);
}
out_paramater_set.Parameter.arrayLen = in_parameter_set.parameter.size();
out_parameter_set.Parameter.arrayLen = in_parameter_set.parameter.size();
}

out.ServiceParameterList.ParameterSet.arrayLen = in.service_parameter_list.size();
Expand All @@ -179,7 +183,7 @@ template <> void insert_type(VariantAccess& va, const struct iso20_ServiceDetail
}

template <> int serialize_to_exi(const ServiceDetailResponse& in, exi_bitstream_t& out) {
iso20_exiDocument doc;
iso20_exiDocument doc{};
init_iso20_exiDocument(&doc);

CB_SET_USED(doc.ServiceDetailRes);
Expand Down
3 changes: 2 additions & 1 deletion test/exi/cb/iso20/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ SCENARIO("Se/Deserialize authorization messages") {
REQUIRE(header.timestamp == 1691411798);

REQUIRE(msg.selected_authorization_service == message_20::Authorization::EIM);
REQUIRE(msg.eim_as_req_authorization_mode.has_value() == true);
REQUIRE(std::holds_alternative<message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode>(
msg.authorization_mode));
}
}

Expand Down
10 changes: 5 additions & 5 deletions test/iso15118/states/authorization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ SCENARIO("Authorization state handling") {
req.header.timestamp = 1691411798;

req.selected_authorization_service = message_20::Authorization::EIM;
req.eim_as_req_authorization_mode.emplace();
req.authorization_mode = message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode{};

const auto res = d20::state::handle_request(req, d20::Session(), AuthStatus::Pending);

Expand All @@ -37,7 +37,7 @@ SCENARIO("Authorization state handling") {
req.header.timestamp = 1691411798;

req.selected_authorization_service = message_20::Authorization::EIM;
req.eim_as_req_authorization_mode.emplace();
req.authorization_mode = message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode{};

const auto res = d20::state::handle_request(req, session, AuthStatus::Pending);

Expand All @@ -59,7 +59,7 @@ SCENARIO("Authorization state handling") {
req.header.timestamp = 1691411798;

req.selected_authorization_service = message_20::Authorization::EIM;
req.eim_as_req_authorization_mode.emplace();
req.authorization_mode = message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode{};

const auto res = d20::state::handle_request(req, session, AuthStatus::Rejected);

Expand All @@ -79,7 +79,7 @@ SCENARIO("Authorization state handling") {
req.header.timestamp = 1691411798;

req.selected_authorization_service = message_20::Authorization::EIM;
req.eim_as_req_authorization_mode.emplace();
req.authorization_mode = message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode{};

const auto res = d20::state::handle_request(req, session, AuthStatus::Pending);

Expand All @@ -99,7 +99,7 @@ SCENARIO("Authorization state handling") {
req.header.timestamp = 1691411798;

req.selected_authorization_service = message_20::Authorization::EIM;
req.eim_as_req_authorization_mode.emplace();
req.authorization_mode = message_20::AuthorizationRequest::EIM_ASReqAuthorizationMode{};

const auto res = d20::state::handle_request(req, session, AuthStatus::Accepted);

Expand Down
Loading