📄 en50221.c
字号:
/***************************************************************************** * en50221.c : implementation of the transport, session and applications * layers of EN 50 221 ***************************************************************************** * Copyright (C) 2004 VideoLAN * * Authors: Christophe Massiot <massiot@via.ecp.fr> * Based on code from libdvbci Copyright (C) 2000 Klaus Schmidinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************/#include <vlc/vlc.h>#include <vlc/input.h>#include <sys/ioctl.h>#include <errno.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#include <sys/poll.h>/* DVB Card Drivers */#include <linux/dvb/version.h>#include <linux/dvb/dmx.h>#include <linux/dvb/frontend.h>#include <linux/dvb/ca.h>/* Include dvbpsi headers */#ifdef HAVE_DVBPSI_DR_H# include <dvbpsi/dvbpsi.h># include <dvbpsi/descriptor.h># include <dvbpsi/pat.h># include <dvbpsi/pmt.h># include <dvbpsi/dr.h># include <dvbpsi/psi.h>#else# include "dvbpsi.h"# include "descriptor.h"# include "tables/pat.h"# include "tables/pmt.h"# include "descriptors/dr.h"# include "psi.h"#endif#include "dvb.h"#undef DEBUG_TPDUstatic void ResourceManagerOpen( access_t * p_access, int i_session_id );static void ApplicationInformationOpen( access_t * p_access, int i_session_id );static void ConditionalAccessOpen( access_t * p_access, int i_session_id );static void DateTimeOpen( access_t * p_access, int i_session_id );static void MMIOpen( access_t * p_access, int i_session_id );/***************************************************************************** * Utility functions *****************************************************************************/#define SIZE_INDICATOR 0x80static uint8_t *GetLength( uint8_t *p_data, int *pi_length ){ *pi_length = *p_data++; if ( (*pi_length & SIZE_INDICATOR) != 0 ) { int l = *pi_length & ~SIZE_INDICATOR; int i; *pi_length = 0; for ( i = 0; i < l; i++ ) *pi_length = (*pi_length << 8) | *p_data++; } return p_data;}static uint8_t *SetLength( uint8_t *p_data, int i_length ){ uint8_t *p = p_data; if ( i_length < 128 ) { *p++ = i_length; } else if ( i_length < 256 ) { *p++ = SIZE_INDICATOR | 0x1; *p++ = i_length; } else if ( i_length < 65536 ) { *p++ = SIZE_INDICATOR | 0x2; *p++ = i_length >> 8; *p++ = i_length & 0xff; } else if ( i_length < 16777216 ) { *p++ = SIZE_INDICATOR | 0x3; *p++ = i_length >> 16; *p++ = (i_length >> 8) & 0xff; *p++ = i_length & 0xff; } else { *p++ = SIZE_INDICATOR | 0x4; *p++ = i_length >> 24; *p++ = (i_length >> 16) & 0xff; *p++ = (i_length >> 8) & 0xff; *p++ = i_length & 0xff; } return p;}/* * Transport layer */#define MAX_TPDU_SIZE 2048#define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)#define DATA_INDICATOR 0x80#define T_SB 0x80#define T_RCV 0x81#define T_CREATE_TC 0x82#define T_CTC_REPLY 0x83#define T_DELETE_TC 0x84#define T_DTC_REPLY 0x85#define T_REQUEST_TC 0x86#define T_NEW_TC 0x87#define T_TC_ERROR 0x88#define T_DATA_LAST 0xA0#define T_DATA_MORE 0xA1static void Dump( vlc_bool_t b_outgoing, uint8_t *p_data, int i_size ){#ifdef DEBUG_TPDU int i;#define MAX_DUMP 256 fprintf(stderr, "%s ", b_outgoing ? "-->" : "<--"); for ( i = 0; i < i_size && i < MAX_DUMP; i++) fprintf(stderr, "%02X ", p_data[i]); fprintf(stderr, "%s\n", i_size >= MAX_DUMP ? "..." : "");#endif}/***************************************************************************** * TPDUSend *****************************************************************************/static int TPDUSend( access_t * p_access, uint8_t i_slot, uint8_t i_tag, const uint8_t *p_content, int i_length ){ access_sys_t *p_sys = p_access->p_sys; uint8_t i_tcid = i_slot + 1; uint8_t p_data[MAX_TPDU_SIZE]; int i_size; i_size = 0; p_data[0] = i_slot; p_data[1] = i_tcid; p_data[2] = i_tag; switch ( i_tag ) { case T_RCV: case T_CREATE_TC: case T_CTC_REPLY: case T_DELETE_TC: case T_DTC_REPLY: case T_REQUEST_TC: p_data[3] = 1; /* length */ p_data[4] = i_tcid; i_size = 5; break; case T_NEW_TC: case T_TC_ERROR: p_data[3] = 2; /* length */ p_data[4] = i_tcid; p_data[5] = p_content[0]; i_size = 6; break; case T_DATA_LAST: case T_DATA_MORE: { /* i_length <= MAX_TPDU_DATA */ uint8_t *p = p_data + 3; p = SetLength( p, i_length + 1 ); *p++ = i_tcid; if ( i_length ) memcpy( p, p_content, i_length ); i_size = i_length + (p - p_data); } break; default: break; } Dump( VLC_TRUE, p_data, i_size ); if ( write( p_sys->i_ca_handle, p_data, i_size ) != i_size ) { msg_Err( p_access, "cannot write to CAM device (%s)", strerror(errno) ); return VLC_EGENERIC; } return VLC_SUCCESS;}/***************************************************************************** * TPDURecv *****************************************************************************/#define CAM_READ_TIMEOUT 3500 // msstatic int TPDURecv( access_t * p_access, uint8_t i_slot, uint8_t *pi_tag, uint8_t *p_data, int *pi_size ){ access_sys_t *p_sys = p_access->p_sys; uint8_t i_tcid = i_slot + 1; int i_size; struct pollfd pfd[1]; pfd[0].fd = p_sys->i_ca_handle; pfd[0].events = POLLIN; if ( !(poll(pfd, 1, CAM_READ_TIMEOUT) > 0 && (pfd[0].revents & POLLIN)) ) { msg_Err( p_access, "cannot poll from CAM device" ); return VLC_EGENERIC; } if ( pi_size == NULL ) { p_data = malloc( MAX_TPDU_SIZE ); } for ( ; ; ) { i_size = read( p_sys->i_ca_handle, p_data, MAX_TPDU_SIZE ); if ( i_size >= 0 || errno != EINTR ) break; } if ( i_size < 5 ) { msg_Err( p_access, "cannot read from CAM device (%d:%s)", i_size, strerror(errno) ); return VLC_EGENERIC; } if ( p_data[1] != i_tcid ) { msg_Err( p_access, "invalid read from CAM device (%d instead of %d)", p_data[1], i_tcid ); return VLC_EGENERIC; } *pi_tag = p_data[2]; p_sys->pb_tc_has_data[i_slot] = (i_size >= 4 && p_data[i_size - 4] == T_SB && p_data[i_size - 3] == 2 && (p_data[i_size - 1] & DATA_INDICATOR)) ? VLC_TRUE : VLC_FALSE; Dump( VLC_FALSE, p_data, i_size ); if ( pi_size == NULL ) free( p_data ); else *pi_size = i_size; return VLC_SUCCESS;}/* * Session layer */#define ST_SESSION_NUMBER 0x90#define ST_OPEN_SESSION_REQUEST 0x91#define ST_OPEN_SESSION_RESPONSE 0x92#define ST_CREATE_SESSION 0x93#define ST_CREATE_SESSION_RESPONSE 0x94#define ST_CLOSE_SESSION_REQUEST 0x95#define ST_CLOSE_SESSION_RESPONSE 0x96#define SS_OK 0x00#define SS_NOT_ALLOCATED 0xF0#define RI_RESOURCE_MANAGER 0x00010041#define RI_APPLICATION_INFORMATION 0x00020041#define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041#define RI_HOST_CONTROL 0x00200041#define RI_DATE_TIME 0x00240041#define RI_MMI 0x00400041static int ResourceIdToInt( uint8_t *p_data ){ return ((int)p_data[0] << 24) | ((int)p_data[1] << 16) | ((int)p_data[2] << 8) | p_data[3];}/***************************************************************************** * SPDUSend *****************************************************************************/static int SPDUSend( access_t * p_access, int i_session_id, uint8_t *p_data, int i_size ){ access_sys_t *p_sys = p_access->p_sys; uint8_t *p_spdu = malloc( i_size + 4 ); uint8_t *p = p_spdu; uint8_t i_tag; uint8_t i_slot = p_sys->p_sessions[i_session_id - 1].i_slot; *p++ = ST_SESSION_NUMBER; *p++ = 0x02; *p++ = (i_session_id >> 8); *p++ = i_session_id & 0xff; memcpy( p, p_data, i_size ); i_size += 4; p = p_spdu; while ( i_size > 0 ) { if ( i_size > MAX_TPDU_DATA ) { if ( TPDUSend( p_access, i_slot, T_DATA_MORE, p, MAX_TPDU_DATA ) != VLC_SUCCESS ) { msg_Err( p_access, "couldn't send TPDU on session %d", i_session_id ); free( p_spdu ); return VLC_EGENERIC; } p += MAX_TPDU_DATA; i_size -= MAX_TPDU_DATA; } else { if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p, i_size ) != VLC_SUCCESS ) { msg_Err( p_access, "couldn't send TPDU on session %d", i_session_id ); free( p_spdu ); return VLC_EGENERIC; } i_size = 0; } if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS || i_tag != T_SB ) { msg_Err( p_access, "couldn't recv TPDU on session %d", i_session_id ); free( p_spdu ); return VLC_EGENERIC; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -