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:
parent
e4360f3e04
commit
8198ccca69
@ -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(())
|
||||
}
|
||||
|
111
src/ca/mod.rs
111
src/ca/mod.rs
@ -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)
|
||||
}
|
||||
|
@ -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)),
|
||||
|
@ -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
|
||||
|
@ -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, &[])
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user