1
0
mirror of https://github.com/danog/libdvb.git synced 2024-11-26 20:04:39 +01:00

ca: cleaning, remove slot_id from device

This commit is contained in:
Andrey Dyldin 2021-02-01 21:21:13 +02:00
parent e4360f3e04
commit 8198ccca69
5 changed files with 148 additions and 74 deletions

View File

@ -17,7 +17,7 @@ use {
fn check_ca(path: &Path) -> Result<()> {
println!("CA: {}", path.display());
let ca = CaDevice::open(path, 0)?;
let ca = CaDevice::open(path)?;
Ok(())
}

View File

@ -42,7 +42,8 @@ use {
#[derive(Debug)]
pub struct CaDevice {
file: File,
slot_id: u8,
// TODO: slots vec
}
@ -57,7 +58,6 @@ impl CaDevice {
pub fn reset(&mut self) -> Result<()> {
// CA_RESET
ioctl_none!(#[inline] ca_reset, b'o', 128);
unsafe {
ca_reset(self.as_raw_fd())
}.context("CA: failed to reset")?;
@ -66,49 +66,48 @@ impl CaDevice {
}
#[inline]
pub fn get_slot_id(&self) -> u8 { self.slot_id }
fn get_info(&mut self) -> Result<()> {
let mut caps = CaCaps::default();
pub fn get_caps(&self, caps: &mut CaCaps) -> Result<()> {
// CA_GET_CAP
ioctl_read!(#[inline] ca_get_cap, b'o', 129, CaCaps);
unsafe {
ca_get_cap(self.as_raw_fd(), &mut caps as *mut _)
ca_get_cap(self.as_raw_fd(), caps as *mut _)
}.context("CA: failed to get caps")?;
if caps.slot_num == 0 {
return Ok(());
}
self.reset()?;
let delay = Duration::from_millis(10);
thread::sleep(delay);
/* Only 1 slot with ID 0 */
let mut slot_info = CaSlotInfo::default();
slot_info.num = self.slot_id as i32;
// CA_GET_SLOT_INFO
ioctl_read!(#[inline] ca_get_slot_info, b'o', 130, CaSlotInfo);
unsafe {
ca_get_slot_info(self.as_raw_fd(), &mut slot_info as *mut _)
}.context("CA: failed to get slot info")?;
if slot_info.flags == CA_CI_MODULE_NOT_FOUND {
return Err(anyhow!("CA: module not found"));
}
if slot_info.typ != CA_CI_LINK {
return Err(anyhow!("CA: incompatible interface"));
}
Ok(())
}
pub fn open(path: &Path, slot_id: u8) -> Result<CaDevice> {
/// Gets CA slot information
///
/// If slot is available but not ready returns `false`
/// If slot is ready returns `true`
pub fn get_slot_info(&self, slot_info: &mut CaSlotInfo) -> Result<bool> {
// CA_GET_SLOT_INFO
ioctl_read!(#[inline] ca_get_slot_info, b'o', 130, CaSlotInfo);
unsafe {
ca_get_slot_info(self.as_raw_fd(), slot_info as *mut _)
}.context("CA: failed to get slot info")?;
if slot_info.slot_type != CA_CI_LINK {
return Err(anyhow!("CA: incompatible interface"));
}
match slot_info.flags {
CA_CI_MODULE_PRESENT => {
Ok(false)
}
CA_CI_MODULE_READY => {
Ok(true)
}
CA_CI_MODULE_NOT_FOUND => {
Err(anyhow!("CA: module not found"))
}
_ => {
Err(anyhow!("CA: invalid slot flags"))
}
}
}
pub fn open(path: &Path) -> Result<CaDevice> {
let file = OpenOptions::new()
.read(true)
.write(true)
@ -118,12 +117,44 @@ impl CaDevice {
let mut ca = CaDevice {
file,
slot_id,
};
ca.get_info()?;
ca.reset()?;
tpdu::init(&ca)?;
let delay = Duration::from_millis(50);
thread::sleep(delay);
//
let mut caps = CaCaps::default();
for _ in 0 .. 5 {
ca.get_caps(&mut caps)?;
if caps.slot_num != 0 {
break;
}
thread::sleep(delay);
}
if caps.slot_num == 0 {
return Err(anyhow!("CA: device has no slots"));
}
// TODO: slots vec
let mut slot_info = CaSlotInfo::default();
for slot_id in 0 .. caps.slot_num {
slot_info.slot_num = slot_id;
slot_info.slot_type = 0;
slot_info.flags = 0;
ca.get_slot_info(&mut slot_info)?;
tpdu::init(&ca, slot_id as u8)?;
}
Ok(ca)
}

View File

@ -59,13 +59,13 @@ fn assert_size(spdu: &[u8], size: usize) -> Result<()> {
}
fn handle_session_number(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
fn handle_session_number(ca: &mut CaDevice, _slot_id: u8, spdu: &[u8]) -> Result<()> {
let session_id = u16::from_be_bytes(spdu[2 ..= 3].try_into().unwrap());
apdu::handle(ca, session_id, &spdu[SPDU_HEADER_SIZE ..])
}
fn handle_open_session_request(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
fn handle_open_session_request(ca: &mut CaDevice, slot_id: u8, spdu: &[u8]) -> Result<()> {
assert_size(spdu, 6)?;
let resource_id = u32::from_be_bytes(spdu[2 ..= 5].try_into().unwrap());
@ -83,11 +83,11 @@ fn handle_open_session_request(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
session_id as u8
];
tpdu::send(ca, tpdu::TT_DATA_LAST, &response)
tpdu::send(ca, slot_id, tpdu::TT_DATA_LAST, &response)
}
fn handle_close_session_request(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
fn handle_close_session_request(ca: &mut CaDevice, slot_id: u8, spdu: &[u8]) -> Result<()> {
assert_size(spdu, 4)?;
let session_id = u16::from_be_bytes(spdu[2 ..= 3].try_into().unwrap());
@ -101,11 +101,11 @@ fn handle_close_session_request(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
spdu[3]
];
tpdu::send(ca, tpdu::TT_DATA_LAST, &response)
tpdu::send(ca, slot_id, tpdu::TT_DATA_LAST, &response)
}
fn handle_create_session_response(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
fn handle_create_session_response(ca: &mut CaDevice, _slot_id: u8, spdu: &[u8]) -> Result<()> {
assert_size(spdu, 9)?;
let session_id = u16::from_be_bytes(spdu[7 ..= 8].try_into().unwrap());
@ -119,7 +119,7 @@ fn handle_create_session_response(ca: &mut CaDevice, spdu: &[u8]) -> Result<()>
}
fn handle_close_session_response(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
fn handle_close_session_response(ca: &mut CaDevice, _slot_id: u8, spdu: &[u8]) -> Result<()> {
assert_size(spdu, 5)?;
let session_id = u16::from_be_bytes(spdu[3 ..= 4].try_into().unwrap());
@ -129,30 +129,30 @@ fn handle_close_session_response(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
/// Process received message depends of it tag
pub fn handle(ca: &mut CaDevice, spdu: &[u8]) -> Result<()> {
pub fn handle(ca: &mut CaDevice, slot_id: u8, spdu: &[u8]) -> Result<()> {
if spdu.len() < SPDU_HEADER_SIZE {
return Err(anyhow!("CA SPDU: message is too short"));
}
match spdu[0] {
ST_SESSION_NUMBER => {
handle_session_number(ca, spdu)
handle_session_number(ca, slot_id, spdu)
.context("ST_SESSION_NUMBER failed")
}
ST_OPEN_SESSION_REQUEST => {
handle_open_session_request(ca, spdu)
handle_open_session_request(ca, slot_id, spdu)
.context("ST_OPEN_SESSION_REQUEST failed")
}
ST_CLOSE_SESSION_REQUEST => {
handle_close_session_request(ca, spdu)
handle_close_session_request(ca, slot_id, spdu)
.context("ST_CLOSE_SESSION_REQUEST failed")
}
ST_CREATE_SESSION_RESPONSE => {
handle_create_session_response(ca, spdu)
handle_create_session_response(ca, slot_id, spdu)
.context("ST_CREATE_SESSION_RESPONSE failed")
}
ST_CLOSE_SESSION_RESPONSE => {
handle_close_session_response(ca, spdu)
handle_close_session_response(ca, slot_id, spdu)
.context("ST_CLOSE_SESSION_RESPONSE failed")
}
tag => Err(anyhow!("CA SPDU: invalid tag 0x{:02X}", tag)),

View File

@ -14,15 +14,15 @@ pub use {
mod ca_slot_type {
/// CI high level interface
pub const CA_CI: i32 = 1;
pub const CA_CI: u32 = 1;
/// CI link layer level interface
pub const CA_CI_LINK: i32 = 2;
pub const CA_CI_LINK: u32 = 2;
/// CI physical layer level interface
pub const CA_CI_PHYS: i32 = 4;
pub const CA_CI_PHYS: u32 = 4;
/// built-in descrambler
pub const CA_DESCR: i32 = 8;
pub const CA_DESCR: u32 = 8;
/// simple smart card interface
pub const CA_SC: i32 = 128;
pub const CA_SC: u32 = 128;
}
@ -37,12 +37,12 @@ mod ca_slot_flags {
/// CA slot interface types and info
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug)]
pub struct CaSlotInfo {
/// slot number
pub num: i32,
pub slot_num: u32,
/// slot type - ca_slot_type
pub typ: i32,
pub slot_type: u32,
/// flags applicable to the slot - ca_slot_flags
pub flags: u32,
}
@ -60,18 +60,18 @@ mod ca_descr_type {
/// descrambler types and info
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug)]
pub struct CaDescrInfo {
/// number of available descramblers (keys)
pub num: u32,
pub descr_num: u32,
/// type of supported scrambling system - ca_descr_type
pub typ: u32,
pub descr_type: u32,
}
/// CA slot interface capabilities
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug)]
pub struct CaCaps {
/// total number of CA card and module slots
pub slot_num: u32,
@ -86,7 +86,7 @@ pub struct CaCaps {
/// a message to/from a CI-CAM
#[repr(C)]
#[derive(Debug, Copy, Clone)]
#[derive(Debug)]
pub struct CaMsg {
/// unused
index: u32,
@ -107,7 +107,7 @@ impl Default for CaMsg {
/// CA descrambler control words info
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug)]
pub struct CaDescr {
/// CA Descrambler slot
pub index: u32,
@ -119,7 +119,7 @@ pub struct CaDescr {
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug)]
pub struct CaPid {
pub pid: u32,
/// -1 == disable

View File

@ -27,6 +27,7 @@ use {
super::{
asn1,
CaDevice,
spdu,
},
};
@ -55,8 +56,50 @@ mod ca_tpdu_tag {
}
pub fn _read(ca: &mut CaDevice, data: &[u8]) -> Result<()> {
// TODO: read packet
if data.len() < 4 {
return Err(anyhow!("CA TPDU: invalid packet size"));
}
if data[1] == 0 /* TODO: || data[1] > ca.slots.len() */ {
return Err(anyhow!("CA TPDU: invalid slot id {}", data[1]));
}
let slot_id = data[1] - 1;
let tag = data[2];
match tag {
/* Create Transport Connection reply */
TT_CTC_REPLY => {
// TODO: slot is active now
}
/* Delete Transport Connection reply */
TT_DTC_REPLY => {
//
}
TT_DATA_MORE => {
// TODO: save data to buffer
}
TT_DATA_LAST => {
// TODO: save data to buffer
spdu::handle(ca, slot_id, &[])?;
}
TT_SB => {}
_ => {
return Err(anyhow!("CA TPDU: invalid tag 0x{:02X}", tag));
}
}
Ok(())
}
/// Writes TPDU to the CA device
pub fn send(ca: &CaDevice, tag: u8, data: &[u8]) -> Result<()> {
pub fn send(ca: &CaDevice, slot_id: u8, tag: u8, data: &[u8]) -> Result<()> {
if data.len() >= TPDU_SIZE_MAX {
return Err(anyhow!("CA TPDU: packet is to large"));
}
@ -64,10 +107,10 @@ pub fn send(ca: &CaDevice, tag: u8, data: &[u8]) -> Result<()> {
// TODO: queue and send messages only if module ready
// TODO: timeout
let t_c_id = ca.get_slot_id() + 1;
let t_c_id = slot_id + 1;
let mut header: Vec<u8> = Vec::with_capacity(8);
header.push(ca.get_slot_id());
header.push(slot_id);
header.push(t_c_id);
header.push(tag);
@ -88,6 +131,6 @@ pub fn send(ca: &CaDevice, tag: u8, data: &[u8]) -> Result<()> {
/// Init transport layer for slot
pub fn init(ca: &CaDevice) -> Result<()> {
send(ca, TT_CREATE_TC, &[])
pub fn init(ca: &CaDevice, slot_id: u8) -> Result<()> {
send(ca, slot_id, TT_CREATE_TC, &[])
}