Skip to content

Commit

Permalink
Add Host Configuration
Browse files Browse the repository at this point in the history
This is to change the backend configuration of the PT.
  • Loading branch information
SirVer committed Dec 12, 2023
1 parent bc436f6 commit 10cf627
Show file tree
Hide file tree
Showing 6 changed files with 155 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,
}
43 changes: 43 additions & 0 deletions zvt/src/feig/sequences.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::collections::HashMap;
use std::io::Seek;
use std::io::{Error, ErrorKind};
use std::marker::Unpin;
use std::net::Ipv4Addr;
use std::os::unix::fs::FileExt;
use std::path::{Path, PathBuf};
use std::pin::Pin;
Expand Down Expand Up @@ -213,3 +214,45 @@ 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 ChangeHostConfiguration {
pub fn into_stream<Source>(
password: usize,
ip: Ipv4Addr,
port: u16,
config_byte: u8,
src: &mut PacketTransport<Source>,
) -> Pin<Box<impl Stream<Item = Result<ChangeHostConfigurationResponse>> + '_>>
where
Source: AsyncReadExt + AsyncWriteExt + Unpin + Send,
{
let s = try_stream! {
let packet = super::packets::ChangeConfiguration {
tlv: super::packets::tlv::ChangeConfiguration {
system_information: super::packets::tlv::SystemInformation {
password,
host_configuration_data: Some(super::packets::tlv::HostConfigurationData {
ip: ip.into(),
port,
config_byte,
}),
},
},
};
src.write_packet_with_ack(&packet).await?;

let response = src.read_packet().await?;
src.write_packet(&packets::Ack {}).await?;
yield response;
};
Box::pin(s)
}
}
5 changes: 3 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,7 @@ 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 {
if tag == 0x1f || tag == 0xff {
if bytes.len() < 2 {
Err(ZVTError::IncompleteData)
} else {
Expand Down
44 changes: 44 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,28 @@ async fn partial_reversal(socket: &mut PacketTransport, args: PartialReversalArg
Ok(())
}

async fn change_host_config(
socket: &mut PacketTransport,
password: usize,
args: ChangeHostConfigurationArgs,
) -> Result<()> {
let mut stream = feig::sequences::ChangeHostConfiguration::into_stream(
password,
args.ip,
args.port,
args.configuration_byte,
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 +540,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 10cf627

Please sign in to comment.