00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <vlc/vlc.h>
00026 #include <vlc/input.h>
00027
00028 #include <sys/ioctl.h>
00029 #include <errno.h>
00030
00031 #include <sys/types.h>
00032 #include <sys/stat.h>
00033 #include <fcntl.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <sys/stat.h>
00037 #include <sys/poll.h>
00038
00039
00040 #include <linux/dvb/version.h>
00041 #include <linux/dvb/dmx.h>
00042 #include <linux/dvb/frontend.h>
00043 #include <linux/dvb/ca.h>
00044
00045
00046 #ifdef HAVE_DVBPSI_DR_H
00047 # include <dvbpsi/dvbpsi.h>
00048 # include <dvbpsi/descriptor.h>
00049 # include <dvbpsi/pat.h>
00050 # include <dvbpsi/pmt.h>
00051 # include <dvbpsi/dr.h>
00052 # include <dvbpsi/psi.h>
00053 #else
00054 # include "dvbpsi.h"
00055 # include "descriptor.h"
00056 # include "tables/pat.h"
00057 # include "tables/pmt.h"
00058 # include "descriptors/dr.h"
00059 # include "psi.h"
00060 #endif
00061
00062 #include "dvb.h"
00063
00064 #undef DEBUG_TPDU
00065
00066 static void ResourceManagerOpen( access_t * p_access, int i_session_id );
00067 static void ApplicationInformationOpen( access_t * p_access, int i_session_id );
00068 static void ConditionalAccessOpen( access_t * p_access, int i_session_id );
00069 static void DateTimeOpen( access_t * p_access, int i_session_id );
00070 static void MMIOpen( access_t * p_access, int i_session_id );
00071
00072
00073
00074
00075 #define SIZE_INDICATOR 0x80
00076
00077 static uint8_t *GetLength( uint8_t *p_data, int *pi_length )
00078 {
00079 *pi_length = *p_data++;
00080
00081 if ( (*pi_length & SIZE_INDICATOR) != 0 )
00082 {
00083 int l = *pi_length & ~SIZE_INDICATOR;
00084 int i;
00085
00086 *pi_length = 0;
00087 for ( i = 0; i < l; i++ )
00088 *pi_length = (*pi_length << 8) | *p_data++;
00089 }
00090
00091 return p_data;
00092 }
00093
00094 static uint8_t *SetLength( uint8_t *p_data, int i_length )
00095 {
00096 uint8_t *p = p_data;
00097
00098 if ( i_length < 128 )
00099 {
00100 *p++ = i_length;
00101 }
00102 else if ( i_length < 256 )
00103 {
00104 *p++ = SIZE_INDICATOR | 0x1;
00105 *p++ = i_length;
00106 }
00107 else if ( i_length < 65536 )
00108 {
00109 *p++ = SIZE_INDICATOR | 0x2;
00110 *p++ = i_length >> 8;
00111 *p++ = i_length & 0xff;
00112 }
00113 else if ( i_length < 16777216 )
00114 {
00115 *p++ = SIZE_INDICATOR | 0x3;
00116 *p++ = i_length >> 16;
00117 *p++ = (i_length >> 8) & 0xff;
00118 *p++ = i_length & 0xff;
00119 }
00120 else
00121 {
00122 *p++ = SIZE_INDICATOR | 0x4;
00123 *p++ = i_length >> 24;
00124 *p++ = (i_length >> 16) & 0xff;
00125 *p++ = (i_length >> 8) & 0xff;
00126 *p++ = i_length & 0xff;
00127 }
00128
00129 return p;
00130 }
00131
00132
00133
00134
00135
00136
00137 #define MAX_TPDU_SIZE 2048
00138 #define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4)
00139
00140 #define DATA_INDICATOR 0x80
00141
00142 #define T_SB 0x80
00143 #define T_RCV 0x81
00144 #define T_CREATE_TC 0x82
00145 #define T_CTC_REPLY 0x83
00146 #define T_DELETE_TC 0x84
00147 #define T_DTC_REPLY 0x85
00148 #define T_REQUEST_TC 0x86
00149 #define T_NEW_TC 0x87
00150 #define T_TC_ERROR 0x88
00151 #define T_DATA_LAST 0xA0
00152 #define T_DATA_MORE 0xA1
00153
00154 static void Dump( vlc_bool_t b_outgoing, uint8_t *p_data, int i_size )
00155 {
00156 #ifdef DEBUG_TPDU
00157 int i;
00158 #define MAX_DUMP 256
00159 fprintf(stderr, "%s ", b_outgoing ? "-->" : "<--");
00160 for ( i = 0; i < i_size && i < MAX_DUMP; i++)
00161 fprintf(stderr, "%02X ", p_data[i]);
00162 fprintf(stderr, "%s\n", i_size >= MAX_DUMP ? "..." : "");
00163 #endif
00164 }
00165
00166
00167
00168
00169 static int TPDUSend( access_t * p_access, uint8_t i_slot, uint8_t i_tag,
00170 const uint8_t *p_content, int i_length )
00171 {
00172 access_sys_t *p_sys = p_access->p_sys;
00173 uint8_t i_tcid = i_slot + 1;
00174 uint8_t p_data[MAX_TPDU_SIZE];
00175 int i_size;
00176
00177 i_size = 0;
00178 p_data[0] = i_slot;
00179 p_data[1] = i_tcid;
00180 p_data[2] = i_tag;
00181
00182 switch ( i_tag )
00183 {
00184 case T_RCV:
00185 case T_CREATE_TC:
00186 case T_CTC_REPLY:
00187 case T_DELETE_TC:
00188 case T_DTC_REPLY:
00189 case T_REQUEST_TC:
00190 p_data[3] = 1;
00191 p_data[4] = i_tcid;
00192 i_size = 5;
00193 break;
00194
00195 case T_NEW_TC:
00196 case T_TC_ERROR:
00197 p_data[3] = 2;
00198 p_data[4] = i_tcid;
00199 p_data[5] = p_content[0];
00200 i_size = 6;
00201 break;
00202
00203 case T_DATA_LAST:
00204 case T_DATA_MORE:
00205 {
00206
00207 uint8_t *p = p_data + 3;
00208 p = SetLength( p, i_length + 1 );
00209 *p++ = i_tcid;
00210
00211 if ( i_length )
00212 memcpy( p, p_content, i_length );
00213 i_size = i_length + (p - p_data);
00214 }
00215 break;
00216
00217 default:
00218 break;
00219 }
00220 Dump( VLC_TRUE, p_data, i_size );
00221
00222 if ( write( p_sys->i_ca_handle, p_data, i_size ) != i_size )
00223 {
00224 msg_Err( p_access, "cannot write to CAM device (%s)",
00225 strerror(errno) );
00226 return VLC_EGENERIC;
00227 }
00228
00229 return VLC_SUCCESS;
00230 }
00231
00232
00233
00234
00235
00236 #define CAM_READ_TIMEOUT 3500 // ms
00237
00238 static int TPDURecv( access_t * p_access, uint8_t i_slot, uint8_t *pi_tag,
00239 uint8_t *p_data, int *pi_size )
00240 {
00241 access_sys_t *p_sys = p_access->p_sys;
00242 uint8_t i_tcid = i_slot + 1;
00243 int i_size;
00244 struct pollfd pfd[1];
00245
00246 pfd[0].fd = p_sys->i_ca_handle;
00247 pfd[0].events = POLLIN;
00248 if ( !(poll(pfd, 1, CAM_READ_TIMEOUT) > 0 && (pfd[0].revents & POLLIN)) )
00249 {
00250 msg_Err( p_access, "cannot poll from CAM device" );
00251 return VLC_EGENERIC;
00252 }
00253
00254 if ( pi_size == NULL )
00255 {
00256 p_data = malloc( MAX_TPDU_SIZE );
00257 }
00258
00259 for ( ; ; )
00260 {
00261 i_size = read( p_sys->i_ca_handle, p_data, MAX_TPDU_SIZE );
00262
00263 if ( i_size >= 0 || errno != EINTR )
00264 break;
00265 }
00266
00267 if ( i_size < 5 )
00268 {
00269 msg_Err( p_access, "cannot read from CAM device (%d:%s)", i_size,
00270 strerror(errno) );
00271 return VLC_EGENERIC;
00272 }
00273
00274 if ( p_data[1] != i_tcid )
00275 {
00276 msg_Err( p_access, "invalid read from CAM device (%d instead of %d)",
00277 p_data[1], i_tcid );
00278 return VLC_EGENERIC;
00279 }
00280
00281 *pi_tag = p_data[2];
00282 p_sys->pb_tc_has_data[i_slot] = (i_size >= 4
00283 && p_data[i_size - 4] == T_SB
00284 && p_data[i_size - 3] == 2
00285 && (p_data[i_size - 1] & DATA_INDICATOR))
00286 ? VLC_TRUE : VLC_FALSE;
00287
00288 Dump( VLC_FALSE, p_data, i_size );
00289
00290 if ( pi_size == NULL )
00291 free( p_data );
00292 else
00293 *pi_size = i_size;
00294
00295 return VLC_SUCCESS;
00296 }
00297
00298
00299
00300
00301
00302
00303 #define ST_SESSION_NUMBER 0x90
00304 #define ST_OPEN_SESSION_REQUEST 0x91
00305 #define ST_OPEN_SESSION_RESPONSE 0x92
00306 #define ST_CREATE_SESSION 0x93
00307 #define ST_CREATE_SESSION_RESPONSE 0x94
00308 #define ST_CLOSE_SESSION_REQUEST 0x95
00309 #define ST_CLOSE_SESSION_RESPONSE 0x96
00310
00311 #define SS_OK 0x00
00312 #define SS_NOT_ALLOCATED 0xF0
00313
00314 #define RI_RESOURCE_MANAGER 0x00010041
00315 #define RI_APPLICATION_INFORMATION 0x00020041
00316 #define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041
00317 #define RI_HOST_CONTROL 0x00200041
00318 #define RI_DATE_TIME 0x00240041
00319 #define RI_MMI 0x00400041
00320
00321 static int ResourceIdToInt( uint8_t *p_data )
00322 {
00323 return ((int)p_data[0] << 24) | ((int)p_data[1] << 16)
00324 | ((int)p_data[2] << 8) | p_data[3];
00325 }
00326
00327
00328
00329
00330 static int SPDUSend( access_t * p_access, int i_session_id,
00331 uint8_t *p_data, int i_size )
00332 {
00333 access_sys_t *p_sys = p_access->p_sys;
00334 uint8_t *p_spdu = malloc( i_size + 4 );
00335 uint8_t *p = p_spdu;
00336 uint8_t i_tag;
00337 uint8_t i_slot = p_sys->p_sessions[i_session_id - 1].i_slot;
00338
00339 *p++ = ST_SESSION_NUMBER;
00340 *p++ = 0x02;
00341 *p++ = (i_session_id >> 8);
00342 *p++ = i_session_id & 0xff;
00343
00344 memcpy( p, p_data, i_size );
00345
00346 i_size += 4;
00347 p = p_spdu;
00348
00349 while ( i_size > 0 )
00350 {
00351 if ( i_size > MAX_TPDU_DATA )
00352 {
00353 if ( TPDUSend( p_access, i_slot, T_DATA_MORE, p,
00354 MAX_TPDU_DATA ) != VLC_SUCCESS )
00355 {
00356 msg_Err( p_access, "couldn't send TPDU on session %d",
00357 i_session_id );
00358 free( p_spdu );
00359 return VLC_EGENERIC;
00360 }
00361 p += MAX_TPDU_DATA;
00362 i_size -= MAX_TPDU_DATA;
00363 }
00364 else
00365 {
00366 if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p, i_size )
00367 != VLC_SUCCESS )
00368 {
00369 msg_Err( p_access, "couldn't send TPDU on session %d",
00370 i_session_id );
00371 free( p_spdu );
00372 return VLC_EGENERIC;
00373 }
00374 i_size = 0;
00375 }
00376
00377 if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS
00378 || i_tag != T_SB )
00379 {
00380 msg_Err( p_access, "couldn't recv TPDU on session %d",
00381 i_session_id );
00382 free( p_spdu );
00383 return VLC_EGENERIC;
00384 }
00385 }
00386
00387 free( p_spdu );
00388 return VLC_SUCCESS;
00389 }
00390
00391
00392
00393
00394 static void SessionOpen( access_t * p_access, uint8_t i_slot,
00395 uint8_t *p_spdu, int i_size )
00396 {
00397 access_sys_t *p_sys = p_access->p_sys;
00398 int i_session_id;
00399 int i_resource_id = ResourceIdToInt( &p_spdu[2] );
00400 uint8_t p_response[16];
00401 int i_status = SS_NOT_ALLOCATED;
00402 uint8_t i_tag;
00403
00404 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS; i_session_id++ )
00405 {
00406 if ( !p_sys->p_sessions[i_session_id - 1].i_resource_id )
00407 break;
00408 }
00409 if ( i_session_id == MAX_SESSIONS )
00410 {
00411 msg_Err( p_access, "too many sessions !" );
00412 return;
00413 }
00414 p_sys->p_sessions[i_session_id - 1].i_slot = i_slot;
00415 p_sys->p_sessions[i_session_id - 1].i_resource_id = i_resource_id;
00416 p_sys->p_sessions[i_session_id - 1].pf_close = NULL;
00417 p_sys->p_sessions[i_session_id - 1].pf_manage = NULL;
00418
00419 if ( i_resource_id == RI_RESOURCE_MANAGER
00420 || i_resource_id == RI_APPLICATION_INFORMATION
00421 || i_resource_id == RI_CONDITIONAL_ACCESS_SUPPORT
00422 || i_resource_id == RI_DATE_TIME
00423 || i_resource_id == RI_MMI )
00424 {
00425 i_status = SS_OK;
00426 }
00427
00428 p_response[0] = ST_OPEN_SESSION_RESPONSE;
00429 p_response[1] = 0x7;
00430 p_response[2] = i_status;
00431 p_response[3] = p_spdu[2];
00432 p_response[4] = p_spdu[3];
00433 p_response[5] = p_spdu[4];
00434 p_response[6] = p_spdu[5];
00435 p_response[7] = i_session_id >> 8;
00436 p_response[8] = i_session_id & 0xff;
00437
00438 if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p_response, 9 ) !=
00439 VLC_SUCCESS )
00440 {
00441 msg_Err( p_access,
00442 "SessionOpen: couldn't send TPDU on slot %d", i_slot );
00443 return;
00444 }
00445 if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS )
00446 {
00447 msg_Err( p_access,
00448 "SessionOpen: couldn't recv TPDU on slot %d", i_slot );
00449 return;
00450 }
00451
00452 switch ( i_resource_id )
00453 {
00454 case RI_RESOURCE_MANAGER:
00455 ResourceManagerOpen( p_access, i_session_id ); break;
00456 case RI_APPLICATION_INFORMATION:
00457 ApplicationInformationOpen( p_access, i_session_id ); break;
00458 case RI_CONDITIONAL_ACCESS_SUPPORT:
00459 ConditionalAccessOpen( p_access, i_session_id ); break;
00460 case RI_DATE_TIME:
00461 DateTimeOpen( p_access, i_session_id ); break;
00462 case RI_MMI:
00463 MMIOpen( p_access, i_session_id ); break;
00464
00465 case RI_HOST_CONTROL:
00466 default:
00467 msg_Err( p_access, "unknown resource id (0x%x)", i_resource_id );
00468 p_sys->p_sessions[i_session_id - 1].i_resource_id = 0;
00469 }
00470 }
00471
00472
00473
00474
00475 static void SessionClose( access_t * p_access, int i_session_id )
00476 {
00477 access_sys_t *p_sys = p_access->p_sys;
00478 uint8_t p_response[16];
00479 uint8_t i_tag;
00480 uint8_t i_slot = p_sys->p_sessions[i_session_id - 1].i_slot;
00481
00482 if ( p_sys->p_sessions[i_session_id - 1].pf_close != NULL )
00483 p_sys->p_sessions[i_session_id - 1].pf_close( p_access, i_session_id );
00484 p_sys->p_sessions[i_session_id - 1].i_resource_id = 0;
00485
00486 p_response[0] = ST_CLOSE_SESSION_RESPONSE;
00487 p_response[1] = 0x3;
00488 p_response[2] = SS_OK;
00489 p_response[3] = i_session_id >> 8;
00490 p_response[4] = i_session_id & 0xff;
00491
00492 if ( TPDUSend( p_access, i_slot, T_DATA_LAST, p_response, 5 ) !=
00493 VLC_SUCCESS )
00494 {
00495 msg_Err( p_access,
00496 "SessionOpen: couldn't send TPDU on slot %d", i_slot );
00497 return;
00498 }
00499 if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) != VLC_SUCCESS )
00500 {
00501 msg_Err( p_access,
00502 "SessionOpen: couldn't recv TPDU on slot %d", i_slot );
00503 return;
00504 }
00505 }
00506
00507
00508
00509
00510 static void SPDUHandle( access_t * p_access, uint8_t i_slot,
00511 uint8_t *p_spdu, int i_size )
00512 {
00513 access_sys_t *p_sys = p_access->p_sys;
00514 int i_session_id;
00515
00516 switch ( p_spdu[0] )
00517 {
00518 case ST_SESSION_NUMBER:
00519 if ( i_size <= 4 )
00520 return;
00521 i_session_id = ((int)p_spdu[2] << 8) | p_spdu[3];
00522 p_sys->p_sessions[i_session_id - 1].pf_handle( p_access, i_session_id,
00523 p_spdu + 4, i_size - 4 );
00524 break;
00525
00526 case ST_OPEN_SESSION_REQUEST:
00527 if ( i_size != 6 || p_spdu[1] != 0x4 )
00528 return;
00529 SessionOpen( p_access, i_slot, p_spdu, i_size );
00530 break;
00531
00532 case ST_CLOSE_SESSION_REQUEST:
00533 i_session_id = ((int)p_spdu[2] << 8) | p_spdu[3];
00534 SessionClose( p_access, i_session_id );
00535 break;
00536
00537 default:
00538 break;
00539 }
00540 }
00541
00542
00543
00544
00545
00546
00547 #define AOT_NONE 0x000000
00548 #define AOT_PROFILE_ENQ 0x9F8010
00549 #define AOT_PROFILE 0x9F8011
00550 #define AOT_PROFILE_CHANGE 0x9F8012
00551 #define AOT_APPLICATION_INFO_ENQ 0x9F8020
00552 #define AOT_APPLICATION_INFO 0x9F8021
00553 #define AOT_ENTER_MENU 0x9F8022
00554 #define AOT_CA_INFO_ENQ 0x9F8030
00555 #define AOT_CA_INFO 0x9F8031
00556 #define AOT_CA_PMT 0x9F8032
00557 #define AOT_CA_PMT_REPLY 0x9F8033
00558 #define AOT_TUNE 0x9F8400
00559 #define AOT_REPLACE 0x9F8401
00560 #define AOT_CLEAR_REPLACE 0x9F8402
00561 #define AOT_ASK_RELEASE 0x9F8403
00562 #define AOT_DATE_TIME_ENQ 0x9F8440
00563 #define AOT_DATE_TIME 0x9F8441
00564 #define AOT_CLOSE_MMI 0x9F8800
00565 #define AOT_DISPLAY_CONTROL 0x9F8801
00566 #define AOT_DISPLAY_REPLY 0x9F8802
00567 #define AOT_TEXT_LAST 0x9F8803
00568 #define AOT_TEXT_MORE 0x9F8804
00569 #define AOT_KEYPAD_CONTROL 0x9F8805
00570 #define AOT_KEYPRESS 0x9F8806
00571 #define AOT_ENQ 0x9F8807
00572 #define AOT_ANSW 0x9F8808
00573 #define AOT_MENU_LAST 0x9F8809
00574 #define AOT_MENU_MORE 0x9F880A
00575 #define AOT_MENU_ANSW 0x9F880B
00576 #define AOT_LIST_LAST 0x9F880C
00577 #define AOT_LIST_MORE 0x9F880D
00578 #define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E
00579 #define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F
00580 #define AOT_DISPLAY_MESSAGE 0x9F8810
00581 #define AOT_SCENE_END_MARK 0x9F8811
00582 #define AOT_SCENE_DONE 0x9F8812
00583 #define AOT_SCENE_CONTROL 0x9F8813
00584 #define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814
00585 #define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815
00586 #define AOT_FLUSH_DOWNLOAD 0x9F8816
00587 #define AOT_DOWNLOAD_REPLY 0x9F8817
00588 #define AOT_COMMS_CMD 0x9F8C00
00589 #define AOT_CONNECTION_DESCRIPTOR 0x9F8C01
00590 #define AOT_COMMS_REPLY 0x9F8C02
00591 #define AOT_COMMS_SEND_LAST 0x9F8C03
00592 #define AOT_COMMS_SEND_MORE 0x9F8C04
00593 #define AOT_COMMS_RCV_LAST 0x9F8C05
00594 #define AOT_COMMS_RCV_MORE 0x9F8C06
00595
00596
00597
00598
00599 static int APDUGetTag( const uint8_t *p_apdu, int i_size )
00600 {
00601 if ( i_size >= 3 )
00602 {
00603 int i, t = 0;
00604 for ( i = 0; i < 3; i++ )
00605 t = (t << 8) | *p_apdu++;
00606 return t;
00607 }
00608
00609 return AOT_NONE;
00610 }
00611
00612
00613
00614
00615 static uint8_t *APDUGetLength( uint8_t *p_apdu, int *pi_size )
00616 {
00617 return GetLength( &p_apdu[3], pi_size );
00618 }
00619
00620
00621
00622
00623 static int APDUSend( access_t * p_access, int i_session_id, int i_tag,
00624 uint8_t *p_data, int i_size )
00625 {
00626 uint8_t *p_apdu = malloc( i_size + 12 );
00627 uint8_t *p = p_apdu;
00628 int i_ret;
00629
00630 *p++ = (i_tag >> 16);
00631 *p++ = (i_tag >> 8) & 0xff;
00632 *p++ = i_tag & 0xff;
00633 p = SetLength( p, i_size );
00634 if ( i_size )
00635 memcpy( p, p_data, i_size );
00636
00637 i_ret = SPDUSend( p_access, i_session_id, p_apdu, i_size + p - p_apdu );
00638 free( p_apdu );
00639 return i_ret;
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649 static void ResourceManagerHandle( access_t * p_access, int i_session_id,
00650 uint8_t *p_apdu, int i_size )
00651 {
00652 int i_tag = APDUGetTag( p_apdu, i_size );
00653
00654 switch ( i_tag )
00655 {
00656 case AOT_PROFILE_ENQ:
00657 {
00658 int resources[] = { htonl(RI_RESOURCE_MANAGER),
00659 htonl(RI_APPLICATION_INFORMATION),
00660 htonl(RI_CONDITIONAL_ACCESS_SUPPORT),
00661 htonl(RI_DATE_TIME),
00662 htonl(RI_MMI)
00663 };
00664 APDUSend( p_access, i_session_id, AOT_PROFILE, (uint8_t*)resources,
00665 sizeof(resources) );
00666 break;
00667 }
00668 case AOT_PROFILE:
00669 APDUSend( p_access, i_session_id, AOT_PROFILE_CHANGE, NULL, 0 );
00670 break;
00671
00672 default:
00673 msg_Err( p_access, "unexpected tag in ResourceManagerHandle (0x%x)",
00674 i_tag );
00675 }
00676 }
00677
00678
00679
00680
00681 static void ResourceManagerOpen( access_t * p_access, int i_session_id )
00682 {
00683 access_sys_t *p_sys = p_access->p_sys;
00684
00685 msg_Dbg( p_access, "opening ResourceManager session (%d)", i_session_id );
00686
00687 p_sys->p_sessions[i_session_id - 1].pf_handle = ResourceManagerHandle;
00688
00689 APDUSend( p_access, i_session_id, AOT_PROFILE_ENQ, NULL, 0 );
00690 }
00691
00692
00693
00694
00695
00696
00697
00698
00699 static void ApplicationInformationHandle( access_t * p_access, int i_session_id,
00700 uint8_t *p_apdu, int i_size )
00701 {
00702 int i_tag = APDUGetTag( p_apdu, i_size );
00703
00704 switch ( i_tag )
00705 {
00706 case AOT_APPLICATION_INFO:
00707 {
00708 int i_type, i_manufacturer, i_code;
00709 int l = 0;
00710 uint8_t *d = APDUGetLength( p_apdu, &l );
00711
00712 if ( l < 4 ) break;
00713 p_apdu[l + 4] = '\0';
00714
00715 i_type = *d++;
00716 i_manufacturer = ((int)d[0] << 8) | d[1];
00717 d += 2;
00718 i_code = ((int)d[0] << 8) | d[1];
00719 d += 2;
00720 d = GetLength( d, &l );
00721 d[l] = '\0';
00722 msg_Info( p_access, "CAM: %s, %02X, %04X, %04X",
00723 d, i_type, i_manufacturer, i_code );
00724 break;
00725 }
00726 default:
00727 msg_Err( p_access,
00728 "unexpected tag in ApplicationInformationHandle (0x%x)",
00729 i_tag );
00730 }
00731 }
00732
00733
00734
00735
00736 static void ApplicationInformationOpen( access_t * p_access, int i_session_id )
00737 {
00738 access_sys_t *p_sys = p_access->p_sys;
00739
00740 msg_Dbg( p_access, "opening ApplicationInformation session (%d)", i_session_id );
00741
00742 p_sys->p_sessions[i_session_id - 1].pf_handle = ApplicationInformationHandle;
00743
00744 APDUSend( p_access, i_session_id, AOT_APPLICATION_INFO_ENQ, NULL, 0 );
00745 }
00746
00747
00748
00749
00750
00751 #define MAX_CASYSTEM_IDS 16
00752
00753 typedef struct
00754 {
00755 uint16_t pi_system_ids[MAX_CASYSTEM_IDS + 1];
00756 } system_ids_t;
00757
00758 static vlc_bool_t CheckSystemID( system_ids_t *p_ids, uint16_t i_id )
00759 {
00760 int i = 0;
00761 while ( p_ids->pi_system_ids[i] )
00762 {
00763 if ( p_ids->pi_system_ids[i] == i_id )
00764 return VLC_TRUE;
00765 i++;
00766 }
00767
00768 return VLC_FALSE;
00769 }
00770
00771
00772
00773
00774 static vlc_bool_t CAPMTNeedsDescrambling( dvbpsi_pmt_t *p_pmt )
00775 {
00776 dvbpsi_descriptor_t *p_dr;
00777 dvbpsi_pmt_es_t *p_es;
00778
00779 for( p_dr = p_pmt->p_first_descriptor; p_dr != NULL; p_dr = p_dr->p_next )
00780 {
00781 if( p_dr->i_tag == 0x9 )
00782 {
00783 return VLC_TRUE;
00784 }
00785 }
00786
00787 for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
00788 {
00789 for( p_dr = p_es->p_first_descriptor; p_dr != NULL;
00790 p_dr = p_dr->p_next )
00791 {
00792 if( p_dr->i_tag == 0x9 )
00793 {
00794 return VLC_TRUE;
00795 }
00796 }
00797 }
00798
00799 return VLC_FALSE;
00800 }
00801
00802
00803
00804
00805 static int GetCADSize( system_ids_t *p_ids, dvbpsi_descriptor_t *p_dr )
00806 {
00807 int i_cad_size = 0;
00808
00809 while ( p_dr != NULL )
00810 {
00811 if( p_dr->i_tag == 0x9 )
00812 {
00813 uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
00814 | p_dr->p_data[1];
00815 if ( CheckSystemID( p_ids, i_sysid ) )
00816 i_cad_size += p_dr->i_length + 2;
00817 }
00818 p_dr = p_dr->p_next;
00819 }
00820
00821 return i_cad_size;
00822 }
00823
00824 static uint8_t *CAPMTHeader( system_ids_t *p_ids, uint8_t i_list_mgt,
00825 uint16_t i_program_number, uint8_t i_version,
00826 int i_size, dvbpsi_descriptor_t *p_dr,
00827 uint8_t i_cmd )
00828 {
00829 uint8_t *p_data;
00830
00831 if ( i_size )
00832 p_data = malloc( 7 + i_size );
00833 else
00834 p_data = malloc( 6 );
00835
00836 p_data[0] = i_list_mgt;
00837 p_data[1] = i_program_number >> 8;
00838 p_data[2] = i_program_number & 0xff;
00839 p_data[3] = ((i_version & 0x1f) << 1) | 0x1;
00840
00841 if ( i_size )
00842 {
00843 int i;
00844
00845 p_data[4] = (i_size + 1) >> 8;
00846 p_data[5] = (i_size + 1) & 0xff;
00847 p_data[6] = i_cmd;
00848 i = 7;
00849
00850 while ( p_dr != NULL )
00851 {
00852 if( p_dr->i_tag == 0x9 )
00853 {
00854 uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
00855 | p_dr->p_data[1];
00856 if ( CheckSystemID( p_ids, i_sysid ) )
00857 {
00858 p_data[i] = 0x9;
00859 p_data[i + 1] = p_dr->i_length;
00860 memcpy( &p_data[i + 2], p_dr->p_data, p_dr->i_length );
00861 i += p_dr->i_length + 2;
00862 }
00863 }
00864 p_dr = p_dr->p_next;
00865 }
00866 }
00867 else
00868 {
00869 p_data[4] = 0;
00870 p_data[5] = 0;
00871 }
00872
00873 return p_data;
00874 }
00875
00876 static uint8_t *CAPMTES( system_ids_t *p_ids, uint8_t *p_capmt,
00877 int i_capmt_size, uint8_t i_type, uint16_t i_pid,
00878 int i_size, dvbpsi_descriptor_t *p_dr,
00879 uint8_t i_cmd )
00880 {
00881 uint8_t *p_data;
00882 int i;
00883
00884 if ( i_size )
00885 p_data = realloc( p_capmt, i_capmt_size + 6 + i_size );
00886 else
00887 p_data = realloc( p_capmt, i_capmt_size + 5 );
00888
00889 i = i_capmt_size;
00890
00891 p_data[i] = i_type;
00892 p_data[i + 1] = i_pid >> 8;
00893 p_data[i + 2] = i_pid & 0xff;
00894
00895 if ( i_size )
00896 {
00897 p_data[i + 3] = (i_size + 1) >> 8;
00898 p_data[i + 4] = (i_size + 1) & 0xff;
00899 p_data[i + 5] = i_cmd;
00900 i += 6;
00901
00902 while ( p_dr != NULL )
00903 {
00904 if( p_dr->i_tag == 0x9 )
00905 {
00906 uint16_t i_sysid = ((uint16_t)p_dr->p_data[0] << 8)
00907 | p_dr->p_data[1];
00908 if ( CheckSystemID( p_ids, i_sysid ) )
00909 {
00910 p_data[i] = 0x9;
00911 p_data[i + 1] = p_dr->i_length;
00912 memcpy( &p_data[i + 2], p_dr->p_data, p_dr->i_length );
00913 i += p_dr->i_length + 2;
00914 }
00915 }
00916 p_dr = p_dr->p_next;
00917 }
00918 }
00919 else
00920 {
00921 p_data[i + 3] = 0;
00922 p_data[i + 4] = 0;
00923 }
00924
00925 return p_data;
00926 }
00927
00928 static uint8_t *CAPMTBuild( access_t * p_access, int i_session_id,
00929 dvbpsi_pmt_t *p_pmt, uint8_t i_list_mgt,
00930 uint8_t i_cmd, int *pi_capmt_size )
00931 {
00932 access_sys_t *p_sys = p_access->p_sys;
00933 system_ids_t *p_ids =
00934 (system_ids_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
00935 dvbpsi_pmt_es_t *p_es;
00936 int i_cad_size, i_cad_program_size;
00937 uint8_t *p_capmt;
00938
00939 i_cad_size = i_cad_program_size =
00940 GetCADSize( p_ids, p_pmt->p_first_descriptor );
00941 for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
00942 {
00943 i_cad_size += GetCADSize( p_ids, p_es->p_first_descriptor );
00944 }
00945
00946 if ( !i_cad_size )
00947 {
00948 msg_Warn( p_access,
00949 "no compatible scrambling system for SID %d on session %d",
00950 p_pmt->i_program_number, i_session_id );
00951 *pi_capmt_size = 0;
00952 return NULL;
00953 }
00954
00955 p_capmt = CAPMTHeader( p_ids, i_list_mgt, p_pmt->i_program_number,
00956 p_pmt->i_version, i_cad_program_size,
00957 p_pmt->p_first_descriptor, i_cmd );
00958
00959 if ( i_cad_program_size )
00960 *pi_capmt_size = 7 + i_cad_program_size;
00961 else
00962 *pi_capmt_size = 6;
00963
00964 for( p_es = p_pmt->p_first_es; p_es != NULL; p_es = p_es->p_next )
00965 {
00966 i_cad_size = GetCADSize( p_ids, p_es->p_first_descriptor );
00967
00968 if ( i_cad_size || i_cad_program_size )
00969 {
00970 p_capmt = CAPMTES( p_ids, p_capmt, *pi_capmt_size, p_es->i_type,
00971 p_es->i_pid, i_cad_size,
00972 p_es->p_first_descriptor, i_cmd );
00973 if ( i_cad_size )
00974 *pi_capmt_size += 6 + i_cad_size;
00975 else
00976 *pi_capmt_size += 5;
00977 }
00978 }
00979
00980 return p_capmt;
00981 }
00982
00983
00984
00985
00986 static void CAPMTFirst( access_t * p_access, int i_session_id,
00987 dvbpsi_pmt_t *p_pmt )
00988 {
00989 uint8_t *p_capmt;
00990 int i_capmt_size;
00991
00992 msg_Dbg( p_access, "adding first CAPMT for SID %d on session %d",
00993 p_pmt->i_program_number, i_session_id );
00994
00995 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
00996 0x3 , 0x1 ,
00997 &i_capmt_size );
00998
00999 if ( i_capmt_size )
01000 APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
01001 }
01002
01003
01004
01005
01006 static void CAPMTAdd( access_t * p_access, int i_session_id,
01007 dvbpsi_pmt_t *p_pmt )
01008 {
01009 uint8_t *p_capmt;
01010 int i_capmt_size;
01011
01012 msg_Dbg( p_access, "adding CAPMT for SID %d on session %d",
01013 p_pmt->i_program_number, i_session_id );
01014
01015 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
01016 0x4 , 0x1 ,
01017 &i_capmt_size );
01018
01019 if ( i_capmt_size )
01020 APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
01021 }
01022
01023
01024
01025
01026 static void CAPMTUpdate( access_t * p_access, int i_session_id,
01027 dvbpsi_pmt_t *p_pmt )
01028 {
01029 uint8_t *p_capmt;
01030 int i_capmt_size;
01031
01032 msg_Dbg( p_access, "updating CAPMT for SID %d on session %d",
01033 p_pmt->i_program_number, i_session_id );
01034
01035 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
01036 0x5 , 0x1 ,
01037 &i_capmt_size );
01038
01039 if ( i_capmt_size )
01040 APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
01041 }
01042
01043
01044
01045
01046 static void CAPMTDelete( access_t * p_access, int i_session_id,
01047 dvbpsi_pmt_t *p_pmt )
01048 {
01049 uint8_t *p_capmt;
01050 int i_capmt_size;
01051
01052 msg_Dbg( p_access, "deleting CAPMT for SID %d on session %d",
01053 p_pmt->i_program_number, i_session_id );
01054
01055 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
01056 0x5 , 0x4 ,
01057 &i_capmt_size );
01058
01059 if ( i_capmt_size )
01060 APDUSend( p_access, i_session_id, AOT_CA_PMT, p_capmt, i_capmt_size );
01061 }
01062
01063
01064
01065
01066 static void ConditionalAccessHandle( access_t * p_access, int i_session_id,
01067 uint8_t *p_apdu, int i_size )
01068 {
01069 access_sys_t *p_sys = p_access->p_sys;
01070 system_ids_t *p_ids =
01071 (system_ids_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
01072 int i_tag = APDUGetTag( p_apdu, i_size );
01073
01074 switch ( i_tag )
01075 {
01076 case AOT_CA_INFO:
01077 {
01078 vlc_bool_t b_inited = VLC_FALSE;
01079 int i;
01080 int l = 0;
01081 uint8_t *d = APDUGetLength( p_apdu, &l );
01082 msg_Dbg( p_access, "CA system IDs supported by the application :" );
01083
01084 for ( i = 0; i < l / 2; i++ )
01085 {
01086 p_ids->pi_system_ids[i] = ((uint16_t)d[0] << 8) | d[1];
01087 d += 2;
01088 msg_Dbg( p_access, "- 0x%x", p_ids->pi_system_ids[i] );
01089 }
01090 p_ids->pi_system_ids[i] = 0;
01091
01092 for ( i = 0; i < MAX_PROGRAMS; i++ )
01093 {
01094 if ( p_sys->pp_selected_programs[i] != NULL )
01095 {
01096 if ( b_inited )
01097 CAPMTAdd( p_access, i_session_id,
01098 p_sys->pp_selected_programs[i] );
01099 else
01100 CAPMTFirst( p_access, i_session_id,
01101 p_sys->pp_selected_programs[i] );
01102 b_inited = VLC_TRUE;
01103 }
01104 }
01105 break;
01106 }
01107
01108 default:
01109 msg_Err( p_access,
01110 "unexpected tag in ConditionalAccessHandle (0x%x)",
01111 i_tag );
01112 }
01113 }
01114
01115
01116
01117
01118 static void ConditionalAccessOpen( access_t * p_access, int i_session_id )
01119 {
01120 access_sys_t *p_sys = p_access->p_sys;
01121
01122 msg_Dbg( p_access, "opening ConditionalAccess session (%d)", i_session_id );
01123
01124 p_sys->p_sessions[i_session_id - 1].pf_handle = ConditionalAccessHandle;
01125 p_sys->p_sessions[i_session_id - 1].p_sys = malloc(sizeof(system_ids_t));
01126 memset( p_sys->p_sessions[i_session_id - 1].p_sys, 0,
01127 sizeof(system_ids_t) );
01128
01129 APDUSend( p_access, i_session_id, AOT_CA_INFO_ENQ, NULL, 0 );
01130 }
01131
01132
01133
01134
01135
01136 typedef struct
01137 {
01138 int i_interval;
01139 mtime_t i_last;
01140 } date_time_t;
01141
01142
01143
01144
01145 static void DateTimeSend( access_t * p_access, int i_session_id )
01146 {
01147 access_sys_t *p_sys = p_access->p_sys;
01148 date_time_t *p_date =
01149 (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
01150
01151 time_t t = time(NULL);
01152 struct tm tm_gmt;
01153 struct tm tm_loc;
01154
01155 if ( gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc) )
01156 {
01157 int Y = tm_gmt.tm_year;
01158 int M = tm_gmt.tm_mon + 1;
01159 int D = tm_gmt.tm_mday;
01160 int L = (M == 1 || M == 2) ? 1 : 0;
01161 int MJD = 14956 + D + (int)((Y - L) * 365.25)
01162 + (int)((M + 1 + L * 12) * 30.6001);
01163 uint8_t p_response[7];
01164
01165 #define DEC2BCD(d) (((d / 10) << 4) + (d % 10))
01166
01167 p_response[0] = htons(MJD) >> 8;
01168 p_response[1] = htons(MJD) & 0xff;
01169 p_response[2] = DEC2BCD(tm_gmt.tm_hour);
01170 p_response[3] = DEC2BCD(tm_gmt.tm_min);
01171 p_response[4] = DEC2BCD(tm_gmt.tm_sec);
01172 p_response[5] = htons(tm_loc.tm_gmtoff / 60) >> 8;
01173 p_response[6] = htons(tm_loc.tm_gmtoff / 60) & 0xff;
01174
01175 APDUSend( p_access, i_session_id, AOT_DATE_TIME, p_response, 7 );
01176
01177 p_date->i_last = mdate();
01178 }
01179 }
01180
01181
01182
01183
01184 static void DateTimeHandle( access_t * p_access, int i_session_id,
01185 uint8_t *p_apdu, int i_size )
01186 {
01187 access_sys_t *p_sys = p_access->p_sys;
01188 date_time_t *p_date =
01189 (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
01190
01191 int i_tag = APDUGetTag( p_apdu, i_size );
01192
01193 switch ( i_tag )
01194 {
01195 case AOT_DATE_TIME_ENQ:
01196 {
01197 int l;
01198 const uint8_t *d = APDUGetLength( p_apdu, &l );
01199
01200 if ( l > 0 )
01201 {
01202 p_date->i_interval = *d;
01203 msg_Dbg( p_access, "DateTimeHandle : interval set to %d",
01204 p_date->i_interval );
01205 }
01206 else
01207 p_date->i_interval = 0;
01208
01209 DateTimeSend( p_access, i_session_id );
01210 break;
01211 }
01212 default:
01213 msg_Err( p_access, "unexpected tag in DateTimeHandle (0x%x)", i_tag );
01214 }
01215 }
01216
01217
01218
01219
01220 static void DateTimeManage( access_t * p_access, int i_session_id )
01221 {
01222 access_sys_t *p_sys = p_access->p_sys;
01223 date_time_t *p_date =
01224 (date_time_t *)p_sys->p_sessions[i_session_id - 1].p_sys;
01225
01226 if ( p_date->i_interval
01227 && mdate() > p_date->i_last + (mtime_t)p_date->i_interval * 1000000 )
01228 {
01229 DateTimeSend( p_access, i_session_id );
01230 }
01231 }
01232
01233
01234
01235
01236 static void DateTimeOpen( access_t * p_access, int i_session_id )
01237 {
01238 access_sys_t *p_sys = p_access->p_sys;
01239
01240 msg_Dbg( p_access, "opening DateTime session (%d)", i_session_id );
01241
01242 p_sys->p_sessions[i_session_id - 1].pf_handle = DateTimeHandle;
01243 p_sys->p_sessions[i_session_id - 1].pf_manage = DateTimeManage;
01244 p_sys->p_sessions[i_session_id - 1].p_sys = malloc(sizeof(date_time_t));
01245 memset( p_sys->p_sessions[i_session_id - 1].p_sys, 0, sizeof(date_time_t) );
01246
01247 DateTimeSend( p_access, i_session_id );
01248 }
01249
01250
01251
01252
01253
01254
01255
01256
01257 static void MMIHandle( access_t * p_access, int i_session_id,
01258 uint8_t *p_apdu, int i_size )
01259 {
01260 int i_tag = APDUGetTag( p_apdu, i_size );
01261
01262 switch ( i_tag )
01263 {
01264 default:
01265 msg_Err( p_access, "unexpected tag in MMIHandle (0x%x)", i_tag );
01266 }
01267 }
01268
01269
01270
01271
01272 static void MMIOpen( access_t * p_access, int i_session_id )
01273 {
01274 access_sys_t *p_sys = p_access->p_sys;
01275
01276 msg_Dbg( p_access, "opening MMI session (%d)", i_session_id );
01277
01278 p_sys->p_sessions[i_session_id - 1].pf_handle = MMIHandle;
01279 }
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289 #define MAX_TC_RETRIES 20
01290
01291 static int InitSlot( access_t * p_access, int i_slot )
01292 {
01293 access_sys_t *p_sys = p_access->p_sys;
01294 int i;
01295
01296 if ( TPDUSend( p_access, i_slot, T_CREATE_TC, NULL, 0 )
01297 != VLC_SUCCESS )
01298 {
01299 msg_Err( p_access, "en50221_Init: couldn't send TPDU on slot %d",
01300 i_slot );
01301 return VLC_EGENERIC;
01302 }
01303
01304
01305 for ( i = 0; i < MAX_TC_RETRIES; i++ )
01306 {
01307 uint8_t i_tag;
01308 if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) == VLC_SUCCESS
01309 && i_tag == T_CTC_REPLY )
01310 {
01311 p_sys->pb_active_slot[i_slot] = VLC_TRUE;
01312 break;
01313 }
01314
01315 if ( TPDUSend( p_access, i_slot, T_CREATE_TC, NULL, 0 )
01316 != VLC_SUCCESS )
01317 {
01318 msg_Err( p_access,
01319 "en50221_Init: couldn't send TPDU on slot %d",
01320 i_slot );
01321 continue;
01322 }
01323 }
01324 if ( p_sys->pb_active_slot[i_slot] )
01325 {
01326 p_sys->i_ca_timeout = 100000;
01327 return VLC_SUCCESS;
01328 }
01329
01330 return VLC_EGENERIC;
01331 }
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341 int E_(en50221_Poll)( access_t * p_access )
01342 {
01343 access_sys_t *p_sys = p_access->p_sys;
01344 int i_slot;
01345 int i_session_id;
01346
01347 for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
01348 {
01349 uint8_t i_tag;
01350
01351 if ( !p_sys->pb_active_slot[i_slot] )
01352 {
01353 ca_slot_info_t sinfo;
01354 sinfo.num = i_slot;
01355 if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
01356 {
01357 msg_Err( p_access, "en50221_Poll: couldn't get info on slot %d",
01358 i_slot );
01359 continue;
01360 }
01361
01362 if ( sinfo.flags & CA_CI_MODULE_READY )
01363 {
01364 msg_Dbg( p_access, "en50221_Poll: slot %d is active",
01365 i_slot );
01366 p_sys->pb_active_slot[i_slot] = VLC_TRUE;
01367 }
01368 else
01369 continue;
01370
01371 InitSlot( p_access, i_slot );
01372 }
01373
01374 if ( !p_sys->pb_tc_has_data[i_slot] )
01375 {
01376 if ( TPDUSend( p_access, i_slot, T_DATA_LAST, NULL, 0 ) !=
01377 VLC_SUCCESS )
01378 {
01379 msg_Err( p_access,
01380 "en50221_Poll: couldn't send TPDU on slot %d",
01381 i_slot );
01382 continue;
01383 }
01384 if ( TPDURecv( p_access, i_slot, &i_tag, NULL, NULL ) !=
01385 VLC_SUCCESS )
01386 {
01387 msg_Err( p_access,
01388 "en50221_Poll: couldn't recv TPDU on slot %d",
01389 i_slot );
01390 continue;
01391 }
01392 }
01393
01394 while ( p_sys->pb_tc_has_data[i_slot] )
01395 {
01396 uint8_t p_tpdu[MAX_TPDU_SIZE];
01397 int i_size, i_session_size;
01398 uint8_t *p_session;
01399
01400 if ( TPDUSend( p_access, i_slot, T_RCV, NULL, 0 ) != VLC_SUCCESS )
01401 {
01402 msg_Err( p_access,
01403 "en50221_Poll: couldn't send TPDU on slot %d",
01404 i_slot );
01405 continue;
01406 }
01407 if ( TPDURecv( p_access, i_slot, &i_tag, p_tpdu, &i_size ) !=
01408 VLC_SUCCESS )
01409 {
01410 msg_Err( p_access,
01411 "en50221_Poll: couldn't recv TPDU on slot %d",
01412 i_slot );
01413 continue;
01414 }
01415
01416 p_session = GetLength( &p_tpdu[3], &i_session_size );
01417 if ( i_session_size <= 1 )
01418 continue;
01419
01420 p_session++;
01421 i_session_size--;
01422
01423 if ( i_tag != T_DATA_LAST )
01424 {
01425 msg_Err( p_access,
01426 "en50221_Poll: fragmented TPDU not supported" );
01427 break;
01428 }
01429
01430 SPDUHandle( p_access, i_slot, p_session, i_session_size );
01431 }
01432 }
01433
01434 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS; i_session_id++ )
01435 {
01436 if ( p_sys->p_sessions[i_session_id - 1].i_resource_id
01437 && p_sys->p_sessions[i_session_id - 1].pf_manage )
01438 {
01439 p_sys->p_sessions[i_session_id - 1].pf_manage( p_access,
01440 i_session_id );
01441 }
01442 }
01443
01444 return VLC_SUCCESS;
01445 }
01446
01447
01448
01449
01450
01451 int E_(en50221_SetCAPMT)( access_t * p_access, dvbpsi_pmt_t *p_pmt )
01452 {
01453 access_sys_t *p_sys = p_access->p_sys;
01454 int i, i_session_id;
01455 vlc_bool_t b_update = VLC_FALSE;
01456 vlc_bool_t b_needs_descrambling = CAPMTNeedsDescrambling( p_pmt );
01457
01458 for ( i = 0; i < MAX_PROGRAMS; i++ )
01459 {
01460 if ( p_sys->pp_selected_programs[i] != NULL
01461 && p_sys->pp_selected_programs[i]->i_program_number
01462 == p_pmt->i_program_number )
01463 {
01464 b_update = VLC_TRUE;
01465
01466 if ( !b_needs_descrambling )
01467 {
01468 dvbpsi_DeletePMT( p_pmt );
01469 p_pmt = p_sys->pp_selected_programs[i];
01470 p_sys->pp_selected_programs[i] = NULL;
01471 }
01472 else
01473 {
01474 dvbpsi_DeletePMT( p_sys->pp_selected_programs[i] );
01475 p_sys->pp_selected_programs[i] = p_pmt;
01476 }
01477
01478 break;
01479 }
01480 }
01481
01482 if ( !b_update && b_needs_descrambling )
01483 {
01484 for ( i = 0; i < MAX_PROGRAMS; i++ )
01485 {
01486 if ( p_sys->pp_selected_programs[i] == NULL )
01487 {
01488 p_sys->pp_selected_programs[i] = p_pmt;
01489 break;
01490 }
01491 }
01492 }
01493
01494 if ( b_update || b_needs_descrambling )
01495 {
01496 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS; i_session_id++ )
01497 {
01498 if ( p_sys->p_sessions[i_session_id - 1].i_resource_id
01499 == RI_CONDITIONAL_ACCESS_SUPPORT )
01500 {
01501 if ( b_update && b_needs_descrambling )
01502 CAPMTUpdate( p_access, i_session_id, p_pmt );
01503 else if ( b_update )
01504 CAPMTDelete( p_access, i_session_id, p_pmt );
01505 else
01506 CAPMTAdd( p_access, i_session_id, p_pmt );
01507 }
01508 }
01509 }
01510
01511 if ( !b_needs_descrambling )
01512 {
01513 dvbpsi_DeletePMT( p_pmt );
01514 }
01515
01516 return VLC_SUCCESS;
01517 }
01518
01519
01520
01521
01522 void E_(en50221_End)( access_t * p_access )
01523 {
01524 access_sys_t *p_sys = p_access->p_sys;
01525 int i;
01526
01527 for ( i = 0; i < MAX_PROGRAMS; i++ )
01528 {
01529 if ( p_sys->pp_selected_programs[i] != NULL )
01530 {
01531 dvbpsi_DeletePMT( p_sys->pp_selected_programs[i] );
01532 }
01533 }
01534
01535
01536 }