Skip to content

Commit

Permalink
Add Host Configuration (#12)
Browse files Browse the repository at this point in the history
* Add Host Configuration

This is to change the backend configuration of the PT.

* Addressed reviewer comments.
  • Loading branch information
SirVer authored Dec 13, 2023
1 parent ff3efd5 commit 7fc3ec5
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 2 deletions.
1 change: 1 addition & 0 deletions zvt/data/change_host_config.blob
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
��@4V�Aշiv�
37 changes: 37 additions & 0 deletions zvt/src/feig/packets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,17 @@ pub struct WriteFile {
pub tlv: Option<tlv::WriteFile>,
}

/// Configuration packages. They all use the "Change Configuration" flow, but
/// with vastly different parameters, hence we have one for each flow. The Change Configuration
/// is described in 2.40, but since this is very hardware manufacturer specific, we put this one
/// here. So mostly see cVEND 6.7-6.16.
#[derive(Debug, PartialEq, Zvt)]
#[zvt_control_field(class = 0x08, instr = 0x13)]
pub struct ChangeConfiguration {
#[zvt_bmp(number = 0x06, length = length::Tlv)]
pub tlv: tlv::ChangeConfiguration,
}

/// Feig, 5.1
#[derive(Debug, PartialEq, Zvt)]
#[zvt_control_field(class = 0x0f, instr = 0xa1)]
Expand All @@ -86,6 +97,7 @@ mod test {
use super::*;
use crate::packets::tests::get_bytes;
use crate::ZvtSerializer;
use std::net::Ipv4Addr;

#[test]
fn test_request_for_data() {
Expand Down Expand Up @@ -230,4 +242,29 @@ mod test {
let actual_bytes = expected.zvt_serialize();
assert_eq!(actual_bytes[..26], bytes[..26]);
}

#[test]
fn test_change_host_config() {
let bytes = get_bytes("change_host_config.blob");
let addr = Ipv4Addr::new(213, 183, 19, 105);
let addr_u32: u32 = addr.into();

let expected = ChangeConfiguration {
tlv: tlv::ChangeConfiguration {
system_information: tlv::SystemInformation {
password: 123456,
host_configuration_data: Some(tlv::HostConfigurationData {
ip: addr_u32,
port: 30401,
config_byte: 1,
}),
},
},
};
assert_eq!(
ChangeConfiguration::zvt_deserialize(&bytes).unwrap().0,
expected
);
assert_eq!(bytes, expected.zvt_serialize());
}
}
27 changes: 27 additions & 0 deletions zvt/src/feig/packets/tlv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,30 @@ pub struct WriteFile {
#[zvt_tlv(tag = 0x2d)]
pub files: Vec<File>,
}

#[derive(Debug, PartialEq, Zvt, Default)]
pub struct HostConfigurationData {
#[zvt_bmp(encoding = encoding::BigEndian)]
pub ip: u32,

#[zvt_bmp(encoding = encoding::BigEndian)]
pub port: u16,

#[zvt_bmp(encoding = encoding::BigEndian)]
pub config_byte: u8,
}

#[derive(Debug, PartialEq, Zvt, Default)]
pub struct SystemInformation {
#[zvt_tlv(encoding = encoding::Bcd, tag = 0xff40)]
pub password: usize,

#[zvt_tlv(tag = 0xff41)]
pub host_configuration_data: Option<HostConfigurationData>,
}

#[derive(Debug, PartialEq, Zvt, Default)]
pub struct ChangeConfiguration {
#[zvt_tlv(tag = 0xe4)]
pub system_information: SystemInformation,
}
13 changes: 13 additions & 0 deletions zvt/src/feig/sequences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,16 @@ impl Sequence for FactoryReset {
type Input = super::packets::CVendFunctions;
type Output = FactoryResetResponse;
}

pub struct ChangeHostConfiguration;

#[derive(Debug, ZvtEnum)]
pub enum ChangeHostConfigurationResponse {
CompletionData(packets::CompletionData),
Abort(packets::Abort),
}

impl Sequence for ChangeHostConfiguration {
type Input = super::packets::ChangeConfiguration;
type Output = ChangeHostConfigurationResponse;
}
9 changes: 7 additions & 2 deletions zvt_builder/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ impl Encoding<NaiveDateTime> for Default {
/// The default is when the [Tag] is used as a Bmp-number or as a Tlv-tag.
impl encoding::Encoding<Tag> for Default {
fn encode(input: &Tag) -> Vec<u8> {
if (input.0 >> 8) == 0x1f {
let low = input.0 >> 8;
if low == 0x1f || low == 0xff {
input.0.to_be_bytes().to_vec()
} else {
vec![input.0 as u8]
Expand All @@ -151,7 +152,11 @@ impl encoding::Encoding<Tag> for Default {

fn decode(bytes: &[u8]) -> ZVTResult<(Tag, &[u8])> {
let (tag, new_bytes): (u8, _) = encoding::BigEndian::decode(bytes)?;
if tag == 0x1f {
// §9.4.1 of the PA00P015 defines a lot of tags, there is a bunch of 2 byte tags that start
// with 0xf1xx, there is also 0xff01-0xff04 defined there.
// TODO(hrapp): The same section also mentions tags 0x9f5a, 0x9f5b, and three byte tags
// 0x1f8000 and 0x1f8001 which we are not handling correctly currently.
if tag == 0x1f || tag == 0xff {
if bytes.len() < 2 {
Err(ZVTError::IncompleteData)
} else {
Expand Down
51 changes: 51 additions & 0 deletions zvt_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::{bail, Result};
use argh::FromArgs;
use env_logger::{Builder, Env};
use std::io::Write;
use std::net::Ipv4Addr;
use tokio::net::TcpStream;
use tokio_stream::StreamExt;
use zvt::sequences::Sequence;
Expand All @@ -23,6 +24,7 @@ enum SubCommands {
ReadCard(ReadCardArgs),
Reservation(ReservationArgs),
PartialReversal(PartialReversalArgs),
ChangeHostConfiguration(ChangeHostConfigurationArgs),
}

#[derive(FromArgs, PartialEq, Debug)]
Expand Down Expand Up @@ -181,6 +183,23 @@ struct PartialReversalArgs {
bmp_data: Option<String>,
}

#[derive(FromArgs, PartialEq, Debug)]
/// Changes the Host the payment terminal connects to.
#[argh(subcommand, name = "change_host_config")]
struct ChangeHostConfigurationArgs {
/// the IP the terminal should connect to.
#[argh(option)]
ip: Ipv4Addr,

/// the port the terminal should connect to.
#[argh(option, default = "30401")]
port: u16,

/// see reservation.
#[argh(option, default = "1")]
configuration_byte: u8,
}

#[derive(FromArgs, Debug)]
/// Example tool to interact with the payment terminal.
struct Args {
Expand Down Expand Up @@ -477,6 +496,35 @@ async fn partial_reversal(socket: &mut PacketTransport, args: PartialReversalArg
Ok(())
}

async fn change_host_config(
socket: &mut PacketTransport,
password: usize,
args: ChangeHostConfigurationArgs,
) -> Result<()> {
let request = feig::packets::ChangeConfiguration {
tlv: feig::packets::tlv::ChangeConfiguration {
system_information: feig::packets::tlv::SystemInformation {
password,
host_configuration_data: Some(feig::packets::tlv::HostConfigurationData {
ip: args.ip.into(),
port: args.port,
config_byte: args.configuration_byte,
}),
},
},
};

let mut stream = feig::sequences::ChangeHostConfiguration::into_stream(&request, socket);
use feig::sequences::ChangeHostConfigurationResponse::*;
while let Some(response) = stream.next().await {
match response? {
CompletionData(_) => (),
Abort(data) => bail!("Received Abort: {:?}", data),
}
}
Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
init_logger();
Expand All @@ -499,6 +547,9 @@ async fn main() -> Result<()> {
SubCommands::ReadCard(a) => read_card(&mut socket, &a).await?,
SubCommands::Reservation(a) => reservation(&mut socket, a).await?,
SubCommands::PartialReversal(a) => partial_reversal(&mut socket, a).await?,
SubCommands::ChangeHostConfiguration(a) => {
change_host_config(&mut socket, args.password, a).await?
}
}

Ok(())
Expand Down

0 comments on commit 7fc3ec5

Please sign in to comment.