Bug Summary

File:en50221.c
Location:line 1762, column 13
Description:Result of 'malloc' is converted to a pointer of type 'char *', which is incompatible with sizeof operand type 'void **'

Annotated Source Code

1/*****************************************************************************
2 * en50221.c : implementation of the transport, session and applications
3 * layers of EN 50 221
4 *****************************************************************************
5 * Copyright (C) 2004-2005, 2010 VideoLAN
6 *
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Based on code from libdvbci Copyright (C) 2000 Klaus Schmidinger
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
24#include "config.h"
25
26#ifdef HAVE_DVB_SUPPORT
27
28#include <stdlib.h>
29#include <stdint.h>
30#include <stdbool.h>
31#include <stddef.h>
32#include <stdio.h>
33#include <unistd.h>
34#include <string.h>
35#include <inttypes.h>
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <fcntl.h>
39#include <sys/ioctl.h>
40#include <sys/socket.h>
41#include <netinet/in.h>
42#include <arpa/inet.h>
43#include <poll.h>
44#include <errno(*__errno_location ()).h>
45#include <time.h>
46
47/* DVB Card Drivers */
48#include <linux1/dvb/version.h>
49#include <linux1/dvb/dmx.h>
50#include <linux1/dvb/frontend.h>
51#include <linux1/dvb/ca.h>
52
53#include <bitstream/mpeg/psi.h>
54#include <bitstream/dvb/ci.h>
55#include <bitstream/dvb/si.h>
56
57#include "dvblast.h"
58#include "en50221.h"
59#include "comm.h"
60
61#define TAB_APPEND( count, tab, p )if( (count) > 0 ) { (tab) = realloc( tab, sizeof( void ** )
* ( (count) + 1 ) ); } else { (tab) = malloc( sizeof( void *
* ) ); } (tab)[count] = (p); (count)++
\
62 if( (count) > 0 ) \
63 { \
64 (tab) = realloc( tab, sizeof( void ** ) * ( (count) + 1 ) ); \
65 } \
66 else \
67 { \
68 (tab) = malloc( sizeof( void ** ) ); \
69 } \
70 (tab)[count] = (p); \
71 (count)++
72
73/*****************************************************************************
74 * Local declarations
75 *****************************************************************************/
76#undef DEBUG_TPDU
77#define CAM_INIT_TIMEOUT15000000 15000000 /* 15 s */
78#undef HLCI_WAIT_CAM_READY
79#define CAPMT_WAIT100 100 /* ms */
80
81typedef struct en50221_msg_t
82{
83 uint8_t *p_data;
84 int i_size;
85 struct en50221_msg_t *p_next;
86} en50221_msg_t;
87
88typedef struct en50221_session_t
89{
90 int i_slot;
91 int i_resource_id;
92 void (* pf_handle)( access_t *, int, uint8_t *, int );
93 void (* pf_close)( access_t *, int );
94 void (* pf_manage)( access_t *, int );
95 void *p_sys;
96} en50221_session_t;
97
98typedef struct ci_slot_t
99{
100 bool_Bool b_active;
101 bool_Bool b_expect_answer;
102 bool_Bool b_has_data;
103 bool_Bool b_mmi_expected;
104 bool_Bool b_mmi_undisplayed;
105
106 /* TPDU reception */
107 en50221_msg_t *p_recv;
108
109 /* TPDU emission */
110 en50221_msg_t *p_send;
111 en50221_msg_t **pp_send_last;
112 uint8_t *p;
113
114 /* InitSlot callback, if not 0 */
115 mtime_t i_init_timeout;
116
117 /* SPDUSend callback, if p_spdu is not NULL */
118 /* SessionOpen callback, if not 0 */
119 int i_pending_session_id;
120} ci_slot_t;
121
122int i_ca_handle = 0;
123int i_ca_type = -1;
124
125static int i_nb_slots = 0;
126static ci_slot_t p_slots[MAX_CI_SLOTS16];
127static en50221_session_t p_sessions[MAX_SESSIONS32];
128
129/*****************************************************************************
130 * Local prototypes
131 *****************************************************************************/
132static void SessionOpenCb( access_t *p_access, uint8_t i_slot );
133static void SPDUHandle( access_t * p_access, uint8_t i_slot,
134 uint8_t *p_spdu, int i_size );
135
136static void ResourceManagerOpen( access_t * p_access, int i_session_id );
137static void ApplicationInformationOpen( access_t * p_access, int i_session_id );
138static void ConditionalAccessOpen( access_t * p_access, int i_session_id );
139static void DateTimeOpen( access_t * p_access, int i_session_id );
140static void MMIOpen( access_t * p_access, int i_session_id );
141
142/*****************************************************************************
143 * Utility functions
144 *****************************************************************************/
145#define SIZE_INDICATOR0x80 0x80
146
147static uint8_t *GetLength( uint8_t *p_data, int *pi_length )
148{
149 *pi_length = *p_data++;
150
151 if ( (*pi_length & SIZE_INDICATOR0x80) != 0 )
152 {
153 int l = *pi_length & ~SIZE_INDICATOR0x80;
154 int i;
155
156 *pi_length = 0;
157 for ( i = 0; i < l; i++ )
158 *pi_length = (*pi_length << 8) | *p_data++;
159 }
160
161 return p_data;
162}
163
164static uint8_t *SetLength( uint8_t *p_data, int i_length )
165{
166 uint8_t *p = p_data;
167
168 if ( i_length < 128 )
169 {
170 *p++ = i_length;
171 }
172 else if ( i_length < 256 )
173 {
174 *p++ = SIZE_INDICATOR0x80 | 0x1;
175 *p++ = i_length;
176 }
177 else if ( i_length < 65536 )
178 {
179 *p++ = SIZE_INDICATOR0x80 | 0x2;
180 *p++ = i_length >> 8;
181 *p++ = i_length & 0xff;
182 }
183 else if ( i_length < 16777216 )
184 {
185 *p++ = SIZE_INDICATOR0x80 | 0x3;
186 *p++ = i_length >> 16;
187 *p++ = (i_length >> 8) & 0xff;
188 *p++ = i_length & 0xff;
189 }
190 else
191 {
192 *p++ = SIZE_INDICATOR0x80 | 0x4;
193 *p++ = i_length >> 24;
194 *p++ = (i_length >> 16) & 0xff;
195 *p++ = (i_length >> 8) & 0xff;
196 *p++ = i_length & 0xff;
197 }
198
199 return p;
200}
201
202
203/*
204 * Transport layer
205 */
206
207#define MAX_TPDU_SIZE4096 4096
208#define MAX_TPDU_DATA(4096 - 7) (MAX_TPDU_SIZE4096 - 7)
209
210#define DATA_INDICATOR0x80 0x80
211
212#define T_SB0x80 0x80
213#define T_RCV0x81 0x81
214#define T_CREATE_TC0x82 0x82
215#define T_CTC_REPLY0x83 0x83
216#define T_DELETE_TC0x84 0x84
217#define T_DTC_REPLY0x85 0x85
218#define T_REQUEST_TC0x86 0x86
219#define T_NEW_TC0x87 0x87
220#define T_TC_ERROR0x88 0x88
221#define T_DATA_LAST0xA0 0xA0
222#define T_DATA_MORE0xA1 0xA1
223
224static void Dump( bool_Bool b_outgoing, uint8_t *p_data, int i_size )
225{
226#ifdef DEBUG_TPDU
227 int i;
228#define MAX_DUMP 256
229 fprintf(stderrstderr, "%s ", b_outgoing ? "-->" : "<--");
230 for ( i = 0; i < i_size && i < MAX_DUMP; i++)
231 fprintf(stderrstderr, "%02X ", p_data[i]);
232 fprintf(stderrstderr, "%s\n", i_size >= MAX_DUMP ? "..." : "");
233#endif
234}
235
236/*****************************************************************************
237 * TPDUWrite
238 *****************************************************************************/
239static int TPDUWrite( access_t * p_access, uint8_t i_slot )
240{
241 ci_slot_t *p_slot = &p_slots[i_slot];
242 en50221_msg_t *p_send = p_slot->p_send;
243
244 if ( p_slot->b_expect_answer )
245 msg_Warn( p_access,
246 "en50221: writing while expecting an answer on slot %u",
247 i_slot );
248 if ( p_send == NULL((void*)0) )
249 {
250 msg_Warn( p_access, "en50221: no data to write on slot %u !", i_slot );
251 return -1;
252 }
253 p_slot->p_send = p_send->p_next;
254 if ( p_slot->p_send == NULL((void*)0) )
255 p_slot->pp_send_last = &p_slot->p_send;
256
257 Dump( true1, p_send->p_data, p_send->i_size );
258
259 if ( write( i_ca_handle, p_send->p_data, p_send->i_size )
260 != p_send->i_size )
261 {
262 msg_Err( p_access, "en50221: cannot write to CAM device (%m)" );
263 free( p_send->p_data );
264 free( p_send );
265 return -1;
266 }
267
268 free( p_send->p_data );
269 free( p_send );
270 p_slot->b_expect_answer = true1;
271
272 return 0;
273}
274
275/*****************************************************************************
276 * TPDUSend
277 *****************************************************************************/
278static int TPDUSend( access_t * p_access, uint8_t i_slot, uint8_t i_tag,
279 const uint8_t *p_content, int i_length )
280{
281 ci_slot_t *p_slot = &p_slots[i_slot];
282 uint8_t i_tcid = i_slot + 1;
283 en50221_msg_t *p_send = malloc( sizeof(en50221_msg_t) );
284 uint8_t *p_data = malloc( MAX_TPDU_SIZE4096 );
285 int i_size;
286
287 i_size = 0;
288 p_data[0] = i_slot;
289 p_data[1] = i_tcid;
290 p_data[2] = i_tag;
291
292 switch ( i_tag )
293 {
294 case T_RCV0x81:
295 case T_CREATE_TC0x82:
296 case T_CTC_REPLY0x83:
297 case T_DELETE_TC0x84:
298 case T_DTC_REPLY0x85:
299 case T_REQUEST_TC0x86:
300 p_data[3] = 1; /* length */
301 p_data[4] = i_tcid;
302 i_size = 5;
303 break;
304
305 case T_NEW_TC0x87:
306 case T_TC_ERROR0x88:
307 p_data[3] = 2; /* length */
308 p_data[4] = i_tcid;
309 p_data[5] = p_content[0];
310 i_size = 6;
311 break;
312
313 case T_DATA_LAST0xA0:
314 case T_DATA_MORE0xA1:
315 {
316 /* i_length <= MAX_TPDU_DATA */
317 uint8_t *p = p_data + 3;
318 p = SetLength( p, i_length + 1 );
319 *p++ = i_tcid;
320
321 if ( i_length )
322 memcpy( p, p_content, i_length );
323 i_size = i_length + (p - p_data);
324 break;
325 }
326
327 default:
328 break;
329 }
330
331 p_send->p_data = p_data;
332 p_send->i_size = i_size;
333 p_send->p_next = NULL((void*)0);
334
335 *p_slot->pp_send_last = p_send;
336 p_slot->pp_send_last = &p_send->p_next;
337
338 if ( !p_slot->b_expect_answer )
339 return TPDUWrite( p_access, i_slot );
340
341 return 0;
342}
343
344
345/*****************************************************************************
346 * TPDURecv
347 *****************************************************************************/
348static int TPDURecv( access_t * p_access )
349{
350 ci_slot_t *p_slot;
351 uint8_t i_tag, i_slot;
352 uint8_t p_data[MAX_TPDU_SIZE4096];
353 int i_size;
354 bool_Bool b_last = false0;
355
356 do
357 {
358 i_size = read( i_ca_handle, p_data, MAX_TPDU_SIZE4096 );
359 }
360 while ( i_size < 0 && errno(*__errno_location ()) == EINTR4 );
361
362 if ( i_size < 5 )
363 {
364 msg_Err( p_access, "en50221: cannot read from CAM device (%d:%m)",
365 i_size );
366 return -1;
367 }
368
369 Dump( false0, p_data, i_size );
370
371 i_slot = p_data[1] - 1;
372 i_tag = p_data[2];
373
374 if ( i_slot >= i_nb_slots )
375 {
376 msg_Warn( p_access, "en50221: TPDU is from an unknown slot %u",
377 i_slot );
378 return -1;
379 }
380 p_slot = &p_slots[i_slot];
381
382 p_slot->b_has_data = !!(p_data[i_size - 4] == T_SB0x80
383 && p_data[i_size - 3] == 2
384 && (p_data[i_size - 1] & DATA_INDICATOR0x80));
385 p_slot->b_expect_answer = false0;
386
387 switch ( i_tag )
388 {
389 case T_CTC_REPLY0x83:
390 p_slot->b_active = true1;
391 p_slot->i_init_timeout = 0;
392 msg_Dbg( p_access, "CI slot %d is active", i_slot );
393 break;
394
395 case T_SB0x80:
396 break;
397
398 case T_DATA_LAST0xA0:
399 b_last = true1;
400 /* intended pass-through */
401 case T_DATA_MORE0xA1:
402 {
403 en50221_msg_t *p_recv;
404 int i_session_size;
405 uint8_t *p_session = GetLength( &p_data[3], &i_session_size );
406
407 if ( i_session_size <= 1 )
408 break;
409 p_session++;
410 i_session_size--;
411
412 if ( p_slot->p_recv == NULL((void*)0) )
413 {
414 p_slot->p_recv = malloc( sizeof(en50221_msg_t) );
415 p_slot->p_recv->p_data = NULL((void*)0);
416 p_slot->p_recv->i_size = 0;
417 }
418
419 p_recv = p_slot->p_recv;
420 p_recv->p_data = realloc( p_recv->p_data,
421 p_recv->i_size + i_session_size );
422 memcpy( &p_recv->p_data[ p_recv->i_size ], p_session, i_session_size );
423 p_recv->i_size += i_session_size;
424
425 if ( b_last )
426 {
427 SPDUHandle( p_access, i_slot, p_recv->p_data, p_recv->i_size );
428 free( p_recv->p_data );
429 free( p_recv );
430 p_slot->p_recv = NULL((void*)0);
431 }
432 break;
433 }
434
435 default:
436 msg_Warn( p_access, "en50221: unhandled R_TPDU tag %u slot %u", i_tag,
437 i_slot );
438 break;
439 }
440
441 if ( !p_slot->b_expect_answer && p_slot->p_send != NULL((void*)0) )
442 TPDUWrite( p_access, i_slot );
443 if ( !p_slot->b_expect_answer && p_slot->i_pending_session_id != 0 )
444 SessionOpenCb( p_access, i_slot );
445 if ( !p_slot->b_expect_answer && p_slot->b_has_data )
446 TPDUSend( p_access, i_slot, T_RCV0x81, NULL((void*)0), 0 );
447
448 return 0;
449}
450
451
452/*
453 * Session layer
454 */
455
456#define ST_SESSION_NUMBER0x90 0x90
457#define ST_OPEN_SESSION_REQUEST0x91 0x91
458#define ST_OPEN_SESSION_RESPONSE0x92 0x92
459#define ST_CREATE_SESSION0x93 0x93
460#define ST_CREATE_SESSION_RESPONSE0x94 0x94
461#define ST_CLOSE_SESSION_REQUEST0x95 0x95
462#define ST_CLOSE_SESSION_RESPONSE0x96 0x96
463
464#define SS_OK0x00 0x00
465#define SS_NOT_ALLOCATED0xF0 0xF0
466
467#define RI_RESOURCE_MANAGER0x00010041 0x00010041
468#define RI_APPLICATION_INFORMATION0x00020041 0x00020041
469#define RI_CONDITIONAL_ACCESS_SUPPORT0x00030041 0x00030041
470#define RI_HOST_CONTROL0x00200041 0x00200041
471#define RI_DATE_TIME0x00240041 0x00240041
472#define RI_MMI0x00400041 0x00400041
473
474static int ResourceIdToInt( uint8_t *p_data )
475{
476 return ((int)p_data[0] << 24) | ((int)p_data[1] << 16)
477 | ((int)p_data[2] << 8) | p_data[3];
478}
479
480/*****************************************************************************
481 * SPDUSend
482 *****************************************************************************/
483static int SPDUSend( access_t *p_access, int i_session_id,
484 uint8_t *p_data, int i_size )
485{
486 uint8_t *p_spdu = malloc( i_size + 4 );
487 uint8_t *p = p_spdu;
488 uint8_t i_slot = p_sessions[i_session_id - 1].i_slot;
489
490 *p++ = ST_SESSION_NUMBER0x90;
491 *p++ = 0x02;
492 *p++ = (i_session_id >> 8);
493 *p++ = i_session_id & 0xff;
494
495 memcpy( p, p_data, i_size );
496
497 i_size += 4;
498 p = p_spdu;
499
500 while ( i_size > 0 )
501 {
502 if ( i_size > MAX_TPDU_DATA(4096 - 7) )
503 {
504 if ( TPDUSend( p_access, i_slot, T_DATA_MORE0xA1, p,
505 MAX_TPDU_DATA(4096 - 7) ) != 0 )
506 {
507 msg_Err( p_access, "couldn't send TPDU on session %d",
508 i_session_id );
509 free( p_spdu );
510 return -1;
511 }
512 p += MAX_TPDU_DATA(4096 - 7);
513 i_size -= MAX_TPDU_DATA(4096 - 7);
514 }
515 else
516 {
517 if ( TPDUSend( p_access, i_slot, T_DATA_LAST0xA0, p, i_size )
518 != 0 )
519 {
520 msg_Err( p_access, "couldn't send TPDU on session %d",
521 i_session_id );
522 free( p_spdu );
523 return -1;
524 }
525 i_size = 0;
526 }
527 }
528
529 free( p_spdu );
530 return 0;
531}
532
533/*****************************************************************************
534 * SessionOpen
535 *****************************************************************************/
536static void SessionOpenCb( access_t *p_access, uint8_t i_slot )
537{
538 ci_slot_t *p_slot = &p_slots[i_slot];
539 int i_session_id = p_slot->i_pending_session_id;
540 int i_resource_id = p_sessions[i_session_id - 1].i_resource_id;
541
542 p_slot->i_pending_session_id = 0;
543
544 switch ( i_resource_id )
545 {
546 case RI_RESOURCE_MANAGER0x00010041:
547 ResourceManagerOpen( p_access, i_session_id ); break;
548 case RI_APPLICATION_INFORMATION0x00020041:
549 ApplicationInformationOpen( p_access, i_session_id ); break;
550 case RI_CONDITIONAL_ACCESS_SUPPORT0x00030041:
551 ConditionalAccessOpen( p_access, i_session_id ); break;
552 case RI_DATE_TIME0x00240041:
553 DateTimeOpen( p_access, i_session_id ); break;
554 case RI_MMI0x00400041:
555 MMIOpen( p_access, i_session_id ); break;
556
557 case RI_HOST_CONTROL0x00200041:
558 default:
559 msg_Err( p_access, "unknown resource id (0x%x)", i_resource_id );
560 p_sessions[i_session_id - 1].i_resource_id = 0;
561 }
562}
563
564static void SessionOpen( access_t * p_access, uint8_t i_slot,
565 uint8_t *p_spdu, int i_size )
566{
567 ci_slot_t *p_slot = &p_slots[i_slot];
568 int i_session_id;
569 int i_resource_id = ResourceIdToInt( &p_spdu[2] );
570 uint8_t p_response[16];
571 int i_status = SS_NOT_ALLOCATED0xF0;
572
573 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
574 {
575 if ( !p_sessions[i_session_id - 1].i_resource_id )
576 break;
577 }
578 if ( i_session_id > MAX_SESSIONS32 )
579 {
580 msg_Err( p_access, "too many sessions !" );
581 return;
582 }
583 p_sessions[i_session_id - 1].i_slot = i_slot;
584 p_sessions[i_session_id - 1].i_resource_id = i_resource_id;
585 p_sessions[i_session_id - 1].pf_close = NULL((void*)0);
586 p_sessions[i_session_id - 1].pf_manage = NULL((void*)0);
587
588 if ( i_resource_id == RI_RESOURCE_MANAGER0x00010041
589 || i_resource_id == RI_APPLICATION_INFORMATION0x00020041
590 || i_resource_id == RI_CONDITIONAL_ACCESS_SUPPORT0x00030041
591 || i_resource_id == RI_DATE_TIME0x00240041
592 || i_resource_id == RI_MMI0x00400041 )
593 {
594 i_status = SS_OK0x00;
595 }
596
597 p_response[0] = ST_OPEN_SESSION_RESPONSE0x92;
598 p_response[1] = 0x7;
599 p_response[2] = i_status;
600 p_response[3] = p_spdu[2];
601 p_response[4] = p_spdu[3];
602 p_response[5] = p_spdu[4];
603 p_response[6] = p_spdu[5];
604 p_response[7] = i_session_id >> 8;
605 p_response[8] = i_session_id & 0xff;
606
607 if ( TPDUSend( p_access, i_slot, T_DATA_LAST0xA0, p_response, 9 ) != 0 )
608 {
609 msg_Err( p_access,
610 "SessionOpen: couldn't send TPDU on slot %d", i_slot );
611 return;
612 }
613
614 if ( p_slot->i_pending_session_id != 0 )
615 msg_Warn( p_access, "overwriting pending session %d",
616 p_slot->i_pending_session_id );
617 p_slot->i_pending_session_id = i_session_id;
618}
619
620#if 0
621/* unused code for the moment - commented out to keep gcc happy */
622/*****************************************************************************
623 * SessionCreate
624 *****************************************************************************/
625static void SessionCreate( access_t * p_access, int i_slot, int i_resource_id )
626{
627 uint8_t p_response[16];
628 uint8_t i_tag;
629 int i_session_id;
630
631 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
632 {
633 if ( !p_sessions[i_session_id - 1].i_resource_id )
634 break;
635 }
636 if ( i_session_id > MAX_SESSIONS32 )
637 {
638 msg_Err( p_access, "too many sessions !" );
639 return;
640 }
641 p_sessions[i_session_id - 1].i_slot = i_slot;
642 p_sessions[i_session_id - 1].i_resource_id = i_resource_id;
643 p_sessions[i_session_id - 1].pf_close = NULL((void*)0);
644 p_sessions[i_session_id - 1].pf_manage = NULL((void*)0);
645 p_sessions[i_session_id - 1].p_sys = NULL((void*)0);
646
647 p_response[0] = ST_CREATE_SESSION0x93;
648 p_response[1] = 0x6;
649 p_response[2] = i_resource_id >> 24;
650 p_response[3] = (i_resource_id >> 16) & 0xff;
651 p_response[4] = (i_resource_id >> 8) & 0xff;
652 p_response[5] = i_resource_id & 0xff;
653 p_response[6] = i_session_id >> 8;
654 p_response[7] = i_session_id & 0xff;
655
656 if ( TPDUSend( p_access, i_slot, T_DATA_LAST0xA0, p_response, 4 ) !=
657 0 )
658 {
659 msg_Err( p_access,
660 "SessionCreate: couldn't send TPDU on slot %d", i_slot );
661 return;
662 }
663}
664#endif
665
666/*****************************************************************************
667 * SessionCreateResponse
668 *****************************************************************************/
669static void SessionCreateResponse( access_t * p_access, uint8_t i_slot,
670 uint8_t *p_spdu, int i_size )
671{
672 int i_status = p_spdu[2];
673 int i_resource_id = ResourceIdToInt( &p_spdu[3] );
674 int i_session_id = ((int)p_spdu[7] << 8) | p_spdu[8];
675
676 if ( i_status != SS_OK0x00 )
677 {
678 msg_Err( p_access, "SessionCreateResponse: failed to open session %d"
679 " resource=0x%x status=0x%x", i_session_id, i_resource_id,
680 i_status );
681 p_sessions[i_session_id - 1].i_resource_id = 0;
682 return;
683 }
684
685 switch ( i_resource_id )
686 {
687 case RI_RESOURCE_MANAGER0x00010041:
688 ResourceManagerOpen( p_access, i_session_id ); break;
689 case RI_APPLICATION_INFORMATION0x00020041:
690 ApplicationInformationOpen( p_access, i_session_id ); break;
691 case RI_CONDITIONAL_ACCESS_SUPPORT0x00030041:
692 ConditionalAccessOpen( p_access, i_session_id ); break;
693 case RI_DATE_TIME0x00240041:
694 DateTimeOpen( p_access, i_session_id ); break;
695 case RI_MMI0x00400041:
696 MMIOpen( p_access, i_session_id ); break;
697
698 case RI_HOST_CONTROL0x00200041:
699 default:
700 msg_Err( p_access, "unknown resource id (0x%x)", i_resource_id );
701 p_sessions[i_session_id - 1].i_resource_id = 0;
702 }
703}
704
705/*****************************************************************************
706 * SessionSendClose
707 *****************************************************************************/
708static void SessionSendClose( access_t * p_access, int i_session_id )
709{
710 uint8_t p_response[16];
711 uint8_t i_slot = p_sessions[i_session_id - 1].i_slot;
712
713 p_response[0] = ST_CLOSE_SESSION_REQUEST0x95;
714 p_response[1] = 0x2;
715 p_response[2] = i_session_id >> 8;
716 p_response[3] = i_session_id & 0xff;
717
718 if ( TPDUSend( p_access, i_slot, T_DATA_LAST0xA0, p_response, 4 ) !=
719 0 )
720 {
721 msg_Err( p_access,
722 "SessionSendClose: couldn't send TPDU on slot %d", i_slot );
723 return;
724 }
725}
726
727/*****************************************************************************
728 * SessionClose
729 *****************************************************************************/
730static void SessionClose( access_t * p_access, int i_session_id )
731{
732 uint8_t p_response[16];
733 uint8_t i_slot = p_sessions[i_session_id - 1].i_slot;
734
735 if ( p_sessions[i_session_id - 1].pf_close != NULL((void*)0) )
736 p_sessions[i_session_id - 1].pf_close( p_access, i_session_id );
737 p_sessions[i_session_id - 1].i_resource_id = 0;
738
739 p_response[0] = ST_CLOSE_SESSION_RESPONSE0x96;
740 p_response[1] = 0x3;
741 p_response[2] = SS_OK0x00;
742 p_response[3] = i_session_id >> 8;
743 p_response[4] = i_session_id & 0xff;
744
745 if ( TPDUSend( p_access, i_slot, T_DATA_LAST0xA0, p_response, 5 ) !=
746 0 )
747 {
748 msg_Err( p_access,
749 "SessionClose: couldn't send TPDU on slot %d", i_slot );
750 return;
751 }
752}
753
754/*****************************************************************************
755 * SPDUHandle
756 *****************************************************************************/
757static void SPDUHandle( access_t * p_access, uint8_t i_slot,
758 uint8_t *p_spdu, int i_size )
759{
760 int i_session_id;
761
762 switch ( p_spdu[0] )
763 {
764 case ST_SESSION_NUMBER0x90:
765 if ( i_size <= 4 )
766 return;
767 i_session_id = (p_spdu[2] << 8) | p_spdu[3];
768 if ( i_session_id <= MAX_SESSIONS32
769 && p_sessions[i_session_id - 1].pf_handle != NULL((void*)0) )
770 p_sessions[i_session_id - 1].pf_handle( p_access, i_session_id,
771 p_spdu + 4, i_size - 4 );
772 break;
773
774 case ST_OPEN_SESSION_REQUEST0x91:
775 if ( i_size != 6 || p_spdu[1] != 0x4 )
776 return;
777 SessionOpen( p_access, i_slot, p_spdu, i_size );
778 break;
779
780 case ST_CREATE_SESSION_RESPONSE0x94:
781 if ( i_size != 9 || p_spdu[1] != 0x7 )
782 return;
783 SessionCreateResponse( p_access, i_slot, p_spdu, i_size );
784 break;
785
786 case ST_CLOSE_SESSION_REQUEST0x95:
787 if ( i_size != 4 || p_spdu[1] != 0x2 )
788 return;
789 i_session_id = ((int)p_spdu[2] << 8) | p_spdu[3];
790 SessionClose( p_access, i_session_id );
791 break;
792
793 case ST_CLOSE_SESSION_RESPONSE0x96:
794 if ( i_size != 5 || p_spdu[1] != 0x3 )
795 return;
796 i_session_id = ((int)p_spdu[3] << 8) | p_spdu[4];
797 if ( p_spdu[2] )
798 {
799 msg_Err( p_access, "closing a session which is not allocated (%d)",
800 i_session_id );
801 }
802 else
803 {
804 if ( p_sessions[i_session_id - 1].pf_close != NULL((void*)0) )
805 p_sessions[i_session_id - 1].pf_close( p_access,
806 i_session_id );
807 p_sessions[i_session_id - 1].i_resource_id = 0;
808 }
809 break;
810
811 default:
812 msg_Err( p_access, "unexpected tag in SPDUHandle (%x)", p_spdu[0] );
813 break;
814 }
815}
816
817
818/*
819 * Application layer
820 */
821
822#define AOT_NONE0x000000 0x000000
823#define AOT_PROFILE_ENQ0x9F8010 0x9F8010
824#define AOT_PROFILE0x9F8011 0x9F8011
825#define AOT_PROFILE_CHANGE0x9F8012 0x9F8012
826#define AOT_APPLICATION_INFO_ENQ0x9F8020 0x9F8020
827#define AOT_APPLICATION_INFO0x9F8021 0x9F8021
828#define AOT_ENTER_MENU0x9F8022 0x9F8022
829#define AOT_CA_INFO_ENQ0x9F8030 0x9F8030
830#define AOT_CA_INFO0x9F8031 0x9F8031
831#define AOT_CA_PMT0x9F8032 0x9F8032
832#define AOT_CA_PMT_REPLY0x9F8033 0x9F8033
833#define AOT_CA_UPDATE0x9F8034 0x9F8034
834#define AOT_TUNE0x9F8400 0x9F8400
835#define AOT_REPLACE0x9F8401 0x9F8401
836#define AOT_CLEAR_REPLACE0x9F8402 0x9F8402
837#define AOT_ASK_RELEASE0x9F8403 0x9F8403
838#define AOT_DATE_TIME_ENQ0x9F8440 0x9F8440
839#define AOT_DATE_TIME0x9F8441 0x9F8441
840#define AOT_CLOSE_MMI0x9F8800 0x9F8800
841#define AOT_DISPLAY_CONTROL0x9F8801 0x9F8801
842#define AOT_DISPLAY_REPLY0x9F8802 0x9F8802
843#define AOT_TEXT_LAST0x9F8803 0x9F8803
844#define AOT_TEXT_MORE0x9F8804 0x9F8804
845#define AOT_KEYPAD_CONTROL0x9F8805 0x9F8805
846#define AOT_KEYPRESS0x9F8806 0x9F8806
847#define AOT_ENQ0x9F8807 0x9F8807
848#define AOT_ANSW0x9F8808 0x9F8808
849#define AOT_MENU_LAST0x9F8809 0x9F8809
850#define AOT_MENU_MORE0x9F880A 0x9F880A
851#define AOT_MENU_ANSW0x9F880B 0x9F880B
852#define AOT_LIST_LAST0x9F880C 0x9F880C
853#define AOT_LIST_MORE0x9F880D 0x9F880D
854#define AOT_SUBTITLE_SEGMENT_LAST0x9F880E 0x9F880E
855#define AOT_SUBTITLE_SEGMENT_MORE0x9F880F 0x9F880F
856#define AOT_DISPLAY_MESSAGE0x9F8810 0x9F8810
857#define AOT_SCENE_END_MARK0x9F8811 0x9F8811
858#define AOT_SCENE_DONE0x9F8812 0x9F8812
859#define AOT_SCENE_CONTROL0x9F8813 0x9F8813
860#define AOT_SUBTITLE_DOWNLOAD_LAST0x9F8814 0x9F8814
861#define AOT_SUBTITLE_DOWNLOAD_MORE0x9F8815 0x9F8815
862#define AOT_FLUSH_DOWNLOAD0x9F8816 0x9F8816
863#define AOT_DOWNLOAD_REPLY0x9F8817 0x9F8817
864#define AOT_COMMS_CMD0x9F8C00 0x9F8C00
865#define AOT_CONNECTION_DESCRIPTOR0x9F8C01 0x9F8C01
866#define AOT_COMMS_REPLY0x9F8C02 0x9F8C02
867#define AOT_COMMS_SEND_LAST0x9F8C03 0x9F8C03
868#define AOT_COMMS_SEND_MORE0x9F8C04 0x9F8C04
869#define AOT_COMMS_RCV_LAST0x9F8C05 0x9F8C05
870#define AOT_COMMS_RCV_MORE0x9F8C06 0x9F8C06
871
872/*****************************************************************************
873 * APDUGetTag
874 *****************************************************************************/
875static int APDUGetTag( const uint8_t *p_apdu, int i_size )
876{
877 if ( i_size >= 3 )
878 {
879 int i, t = 0;
880 for ( i = 0; i < 3; i++ )
881 t = (t << 8) | *p_apdu++;
882 return t;
883 }
884
885 return AOT_NONE0x000000;
886}
887
888/*****************************************************************************
889 * APDUGetLength
890 *****************************************************************************/
891static uint8_t *APDUGetLength( uint8_t *p_apdu, int *pi_size )
892{
893 return GetLength( &p_apdu[3], pi_size );
894}
895
896/*****************************************************************************
897 * APDUSend
898 *****************************************************************************/
899static int APDUSend( access_t * p_access, int i_session_id, int i_tag,
900 uint8_t *p_data, int i_size )
901{
902 uint8_t *p_apdu = malloc( i_size + 12 );
903 uint8_t *p = p_apdu;
904 ca_msg_t ca_msg;
905 int i_ret;
906
907 *p++ = (i_tag >> 16);
908 *p++ = (i_tag >> 8) & 0xff;
909 *p++ = i_tag & 0xff;
910 p = SetLength( p, i_size );
911 if ( i_size )
912 memcpy( p, p_data, i_size );
913 if ( i_ca_type == CA_CI_LINK2 )
914 {
915 i_ret = SPDUSend( p_access, i_session_id, p_apdu, i_size + p - p_apdu );
916 }
917 else
918 {
919 if ( i_size + p - p_apdu > 256 )
920 {
921 msg_Err( p_access, "CAM: apdu overflow" );
922 i_ret = -1;
923 }
924 else
925 {
926 ca_msg.length = i_size + p - p_apdu;
927 if ( i_size == 0 ) ca_msg.length=3;
928 memcpy( ca_msg.msg, p_apdu, i_size + p - p_apdu );
929 i_ret = ioctl(i_ca_handle, CA_SEND_MSG(((1U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((133)) << 0) | ((((sizeof(ca_msg_t)))) << ((0 +
8)+8)))
, &ca_msg );
930 if ( i_ret < 0 )
931 {
932 msg_Err( p_access, "Error sending to CAM: %m" );
933 i_ret = -1;
934 }
935 }
936 }
937 free( p_apdu );
938 return i_ret;
939}
940
941/*
942 * Resource Manager
943 */
944
945/*****************************************************************************
946 * ResourceManagerHandle
947 *****************************************************************************/
948static void ResourceManagerHandle( access_t * p_access, int i_session_id,
949 uint8_t *p_apdu, int i_size )
950{
951 int i_tag = APDUGetTag( p_apdu, i_size );
952
953 switch ( i_tag )
954 {
955 case AOT_PROFILE_ENQ0x9F8010:
956 {
957 int resources[] = { htonl(RI_RESOURCE_MANAGER)(__extension__ ({ unsigned int __v, __x = (0x00010041); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
,
958 htonl(RI_APPLICATION_INFORMATION)(__extension__ ({ unsigned int __v, __x = (0x00020041); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
,
959 htonl(RI_CONDITIONAL_ACCESS_SUPPORT)(__extension__ ({ unsigned int __v, __x = (0x00030041); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
,
960 htonl(RI_DATE_TIME)(__extension__ ({ unsigned int __v, __x = (0x00240041); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
,
961 htonl(RI_MMI)(__extension__ ({ unsigned int __v, __x = (0x00400041); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
962 };
963 APDUSend( p_access, i_session_id, AOT_PROFILE0x9F8011, (uint8_t*)resources,
964 sizeof(resources) );
965 break;
966 }
967 case AOT_PROFILE0x9F8011:
968 APDUSend( p_access, i_session_id, AOT_PROFILE_CHANGE0x9F8012, NULL((void*)0), 0 );
969 break;
970
971 default:
972 msg_Err( p_access, "unexpected tag in ResourceManagerHandle (0x%x)",
973 i_tag );
974 }
975}
976
977/*****************************************************************************
978 * ResourceManagerOpen
979 *****************************************************************************/
980static void ResourceManagerOpen( access_t * p_access, int i_session_id )
981{
982
983 msg_Dbg( p_access, "opening ResourceManager session (%d)", i_session_id );
984
985 p_sessions[i_session_id - 1].pf_handle = ResourceManagerHandle;
986
987 APDUSend( p_access, i_session_id, AOT_PROFILE_ENQ0x9F8010, NULL((void*)0), 0 );
988}
989
990/*
991 * Application Information
992 */
993
994/*****************************************************************************
995 * ApplicationInformationEnterMenu
996 *****************************************************************************/
997static void ApplicationInformationEnterMenu( access_t * p_access,
998 int i_session_id )
999{
1000 int i_slot = p_sessions[i_session_id - 1].i_slot;
1001
1002 msg_Dbg( p_access, "entering MMI menus on session %d", i_session_id );
1003 APDUSend( p_access, i_session_id, AOT_ENTER_MENU0x9F8022, NULL((void*)0), 0 );
1004 p_slots[i_slot].b_mmi_expected = true1;
1005}
1006
1007/*****************************************************************************
1008 * ApplicationInformationHandle
1009 *****************************************************************************/
1010static void ApplicationInformationHandle( access_t * p_access, int i_session_id,
1011 uint8_t *p_apdu, int i_size )
1012{
1013 int i_tag = APDUGetTag( p_apdu, i_size );
1014
1015 switch ( i_tag )
1016 {
1017 case AOT_APPLICATION_INFO0x9F8021:
1018 {
1019 int i_type, i_manufacturer, i_code;
1020 int l = 0;
1021 uint8_t *d = APDUGetLength( p_apdu, &l );
1022
1023 if ( l < 4 ) break;
1024
1025 i_type = *d++;
1026 i_manufacturer = ((int)d[0] << 8) | d[1];
1027 d += 2;
1028 i_code = ((int)d[0] << 8) | d[1];
1029 d += 2;
1030 d = GetLength( d, &l );
1031
1032 {
1033 char *psz_name = malloc(l + 1);
1034 memcpy( psz_name, d, l );
1035 psz_name[l] = '\0';
1036 msg_Info( p_access, "CAM: %s, %02X, %04X, %04X",
1037 psz_name, i_type, i_manufacturer, i_code );
1038 switch (i_print_type)
1039 {
1040 case PRINT_XML:
1041 psz_name = dvb_string_xml_escape(psz_name);
1042 printf("<STATUS type=\"cam\" status=\"1\" cam_name=\"%s\" cam_type=\"%d\" cam_manufacturer=\"%d\" cam_product=\"%d\" />\n",
1043 psz_name, i_type, i_manufacturer, i_code);
1044 break;
1045 default:
1046 printf("CAM: name=%s type=%d manufacturer=%d product=%d\n",
1047 psz_name, i_type, i_manufacturer, i_code);
1048 }
1049 free(psz_name);
1050 }
1051 break;
1052 }
1053 default:
1054 msg_Err( p_access,
1055 "unexpected tag in ApplicationInformationHandle (0x%x)",
1056 i_tag );
1057 }
1058}
1059
1060/*****************************************************************************
1061 * ApplicationInformationOpen
1062 *****************************************************************************/
1063static void ApplicationInformationOpen( access_t * p_access, int i_session_id )
1064{
1065
1066 msg_Dbg( p_access, "opening ApplicationInformation session (%d)", i_session_id );
1067
1068 p_sessions[i_session_id - 1].pf_handle = ApplicationInformationHandle;
1069
1070 APDUSend( p_access, i_session_id, AOT_APPLICATION_INFO_ENQ0x9F8020, NULL((void*)0), 0 );
1071}
1072
1073/*
1074 * Conditional Access
1075 */
1076
1077typedef struct
1078{
1079 int i_nb_system_ids;
1080 uint16_t *pi_system_ids;
1081
1082 int i_selected_programs;
1083 int b_high_level;
1084} system_ids_t;
1085
1086static bool_Bool CheckSystemID( system_ids_t *p_ids, uint16_t i_id )
1087{
1088 int i;
1089 if( p_ids == NULL((void*)0) ) return false0;
1090 if( p_ids->b_high_level ) return true1;
1091
1092 for ( i = 0; i < p_ids->i_nb_system_ids; i++ )
1093 if ( p_ids->pi_system_ids[i] == i_id )
1094 return true1;
1095
1096 return false0;
1097}
1098
1099/*****************************************************************************
1100 * CAPMTBuild
1101 *****************************************************************************/
1102static bool_Bool HasCADescriptors( system_ids_t *p_ids, uint8_t *p_descs )
1103{
1104 const uint8_t *p_desc;
1105 uint16_t j = 0;
1106
1107 while ( (p_desc = descs_get_desc( p_descs, j )) != NULL((void*)0) )
1108 {
1109 uint8_t i_tag = desc_get_tag( p_desc );
1110 j++;
1111
1112 if ( i_tag == 0x9 && desc09_validate( p_desc )
1113 && CheckSystemID( p_ids, desc09_get_sysid( p_desc ) ) )
1114 return true1;
1115 }
1116
1117 return false0;
1118}
1119
1120static void CopyCADescriptors( system_ids_t *p_ids, uint8_t i_cmd,
1121 uint8_t *p_infos, uint8_t *p_descs )
1122{
1123 const uint8_t *p_desc;
1124 uint16_t j = 0, k = 0;
1125
1126 capmti_init( p_infos );
1127 capmti_set_length( p_infos, 0xfff );
1128 capmti_set_cmd( p_infos, i_cmd );
1129
1130 while ( (p_desc = descs_get_desc( p_descs, j )) != NULL((void*)0) )
1131 {
1132 uint8_t i_tag = desc_get_tag( p_desc );
1133 j++;
1134
1135 if ( i_tag == 0x9 && desc09_validate( p_desc )
1136 && CheckSystemID( p_ids, desc09_get_sysid( p_desc ) ) )
1137 {
1138 uint8_t *p_info = capmti_get_info( p_infos, k );
1139 k++;
1140 memcpy( p_info, p_desc,
1141 DESC_HEADER_SIZE2 + desc_get_length( p_desc ) );
1142 }
1143 }
1144
1145 if ( k )
1146 {
1147 uint8_t *p_info = capmti_get_info( p_infos, k );
1148 capmti_set_length( p_infos, p_info - p_infos - DESCS_HEADER_SIZE2 );
1149 }
1150 else
1151 capmti_set_length( p_infos, 0 );
1152}
1153
1154static uint8_t *CAPMTBuild( access_t * p_access, int i_session_id,
1155 uint8_t *p_pmt, uint8_t i_list_mgt,
1156 uint8_t i_cmd, int *pi_capmt_size )
1157{
1158 system_ids_t *p_ids =
1159 (system_ids_t *)p_sessions[i_session_id - 1].p_sys;
1160 uint8_t *p_es;
1161 uint8_t *p_capmt, *p_capmt_n;
1162 uint16_t j, k;
1163 bool_Bool b_has_ca = HasCADescriptors( p_ids, pmt_get_descs( p_pmt ) );
1164 bool_Bool b_has_es = false0;
1165
1166 j = 0;
1167 while ( (p_es = pmt_get_es( p_pmt, j )) != NULL((void*)0) )
1168 {
1169 uint16_t i_pid = pmtn_get_pid( p_es );
1170 j++;
1171
1172 if ( demux_PIDIsSelected( i_pid ) )
1173 {
1174 b_has_es = true1;
1175 b_has_ca = b_has_ca
1176 || HasCADescriptors( p_ids, pmtn_get_descs( p_es ) );
1177 }
1178 }
1179
1180 if ( !b_has_es )
1181 {
1182 *pi_capmt_size = 0;
1183 return NULL((void*)0);
1184 }
1185
1186 if ( !b_has_ca )
1187 {
1188 msg_Warn( p_access,
1189 "no compatible scrambling system for SID %d on session %d",
1190 pmt_get_programpsi_get_tableidext( p_pmt ), i_session_id );
1191 *pi_capmt_size = 0;
1192 return NULL((void*)0);
1193 }
1194
1195 p_capmt = capmt_allocatepsi_private_allocate();
1196 capmt_init( p_capmt );
1197 capmt_set_listmanagement( p_capmt, i_list_mgt );
1198 capmt_set_program( p_capmt, pmt_get_programpsi_get_tableidext( p_pmt ) );
1199 capmt_set_version( p_capmt, psi_get_version( p_pmt ) );
1200
1201 CopyCADescriptors( p_ids, i_cmd, capmt_get_infos( p_capmt ),
1202 pmt_get_descs( p_pmt ) );
1203
1204 j = 0; k = 0;
1205 while ( (p_es = pmt_get_es( p_pmt, j )) != NULL((void*)0) )
1206 {
1207 uint16_t i_pid = pmtn_get_pid( p_es );
1208 j++;
1209
1210 if ( !demux_PIDIsSelected( i_pid ) )
1211 continue;
1212
1213 p_capmt_n = capmt_get_es( p_capmt, k );
1214 k++;
1215
1216 capmtn_init( p_capmt_n );
1217 capmtn_set_streamtype( p_capmt_n, pmtn_get_streamtype( p_es ) );
1218 capmtn_set_pid( p_capmt_n, pmtn_get_pid( p_es ) );
1219
1220 CopyCADescriptors( p_ids, i_cmd, capmtn_get_infos( p_capmt_n ),
1221 pmtn_get_descs( p_es ) );
1222 }
1223
1224 p_capmt_n = capmt_get_es( p_capmt, k );
1225 *pi_capmt_size = p_capmt_n - p_capmt;
1226
1227 return p_capmt;
1228}
1229
1230/*****************************************************************************
1231 * CAPMTFirst
1232 *****************************************************************************/
1233static void CAPMTFirst( access_t * p_access, int i_session_id, uint8_t *p_pmt )
1234{
1235 uint8_t *p_capmt;
1236 int i_capmt_size;
1237
1238 msg_Dbg( p_access, "adding first CAPMT for SID %d on session %d",
1239 pmt_get_programpsi_get_tableidext( p_pmt ), i_session_id );
1240
1241 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
1242 0x3 /* only */, 0x1 /* ok_descrambling */,
1243 &i_capmt_size );
1244
1245 if ( i_capmt_size )
1246 {
1247 APDUSend( p_access, i_session_id, AOT_CA_PMT0x9F8032, p_capmt, i_capmt_size );
1248 free( p_capmt );
1249 }
1250}
1251
1252/*****************************************************************************
1253 * CAPMTAdd
1254 *****************************************************************************/
1255static void CAPMTAdd( access_t * p_access, int i_session_id, uint8_t *p_pmt )
1256{
1257 system_ids_t *p_ids =
1258 (system_ids_t *)p_sessions[i_session_id - 1].p_sys;
1259 uint8_t *p_capmt;
1260 int i_capmt_size;
1261
1262 p_ids->i_selected_programs++;
1263 if( p_ids->i_selected_programs == 1 )
1264 {
1265 CAPMTFirst( p_access, i_session_id, p_pmt );
1266 return;
1267 }
1268
1269 msg_Dbg( p_access, "adding CAPMT for SID %d on session %d",
1270 pmt_get_programpsi_get_tableidext( p_pmt ), i_session_id );
1271
1272 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
1273 0x4 /* add */, 0x1 /* ok_descrambling */,
1274 &i_capmt_size );
1275
1276 if ( i_capmt_size )
1277 {
1278 APDUSend( p_access, i_session_id, AOT_CA_PMT0x9F8032, p_capmt, i_capmt_size );
1279 free( p_capmt );
1280 }
1281}
1282
1283/*****************************************************************************
1284 * CAPMTUpdate
1285 *****************************************************************************/
1286static void CAPMTUpdate( access_t * p_access, int i_session_id, uint8_t *p_pmt )
1287{
1288 uint8_t *p_capmt;
1289 int i_capmt_size;
1290
1291 msg_Dbg( p_access, "updating CAPMT for SID %d on session %d",
1292 pmt_get_programpsi_get_tableidext( p_pmt ), i_session_id );
1293
1294 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
1295 0x5 /* update */, 0x1 /* ok_descrambling */,
1296 &i_capmt_size );
1297
1298 if ( i_capmt_size )
1299 {
1300 APDUSend( p_access, i_session_id, AOT_CA_PMT0x9F8032, p_capmt, i_capmt_size );
1301 free( p_capmt );
1302 }
1303}
1304
1305/*****************************************************************************
1306 * CAPMTDelete
1307 *****************************************************************************/
1308static void CAPMTDelete( access_t * p_access, int i_session_id, uint8_t *p_pmt )
1309{
1310 system_ids_t *p_ids =
1311 (system_ids_t *)p_sessions[i_session_id - 1].p_sys;
1312 uint8_t *p_capmt;
1313 int i_capmt_size;
1314
1315 p_ids->i_selected_programs--;
1316 msg_Dbg( p_access, "deleting CAPMT for SID %d on session %d",
1317 pmt_get_programpsi_get_tableidext( p_pmt ), i_session_id );
1318
1319 p_capmt = CAPMTBuild( p_access, i_session_id, p_pmt,
1320 0x5 /* update */, 0x4 /* not selected */,
1321 &i_capmt_size );
1322
1323 if ( i_capmt_size )
1324 {
1325 APDUSend( p_access, i_session_id, AOT_CA_PMT0x9F8032, p_capmt, i_capmt_size );
1326 free( p_capmt );
1327 }
1328}
1329
1330/*****************************************************************************
1331 * ConditionalAccessHandle
1332 *****************************************************************************/
1333static void ConditionalAccessHandle( access_t * p_access, int i_session_id,
1334 uint8_t *p_apdu, int i_size )
1335{
1336 system_ids_t *p_ids =
1337 (system_ids_t *)p_sessions[i_session_id - 1].p_sys;
1338 int i_tag = APDUGetTag( p_apdu, i_size );
1339
1340 switch ( i_tag )
1341 {
1342 case AOT_CA_INFO0x9F8031:
1343 {
1344 int i;
1345 int l = 0;
1346 uint8_t *d = APDUGetLength( p_apdu, &l );
1347 msg_Dbg( p_access, "CA system IDs supported by the application :" );
1348
1349 if ( p_ids->i_nb_system_ids )
1350 free( p_ids->pi_system_ids );
1351 p_ids->i_nb_system_ids = l / 2;
1352 p_ids->pi_system_ids = malloc( p_ids->i_nb_system_ids
1353 * sizeof(uint16_t) );
1354
1355 for ( i = 0; i < p_ids->i_nb_system_ids; i++ )
1356 {
1357 p_ids->pi_system_ids[i] = ((uint16_t)d[0] << 8) | d[1];
1358 d += 2;
1359 msg_Dbg( p_access, "- 0x%x", p_ids->pi_system_ids[i] );
1360 }
1361
1362 demux_ResendCAPMTs();
1363 break;
1364 }
1365
1366 case AOT_CA_UPDATE0x9F8034:
1367 /* http://www.cablelabs.com/specifications/OC-SP-HOSTPOD-IF-I08-011221.pdf */
1368 case AOT_CA_PMT_REPLY0x9F8033:
1369 /* We do not care */
1370 break;
1371
1372 default:
1373 msg_Err( p_access,
1374 "unexpected tag in ConditionalAccessHandle (0x%x)",
1375 i_tag );
1376 }
1377}
1378
1379/*****************************************************************************
1380 * ConditionalAccessClose
1381 *****************************************************************************/
1382static void ConditionalAccessClose( access_t * p_access, int i_session_id )
1383{
1384
1385 msg_Dbg( p_access, "closing ConditionalAccess session (%d)", i_session_id );
1386
1387 free( p_sessions[i_session_id - 1].p_sys );
1388}
1389
1390/*****************************************************************************
1391 * ConditionalAccessOpen
1392 *****************************************************************************/
1393static void ConditionalAccessOpen( access_t * p_access, int i_session_id )
1394{
1395
1396 msg_Dbg( p_access, "opening ConditionalAccess session (%d)", i_session_id );
1397
1398 p_sessions[i_session_id - 1].pf_handle = ConditionalAccessHandle;
1399 p_sessions[i_session_id - 1].pf_close = ConditionalAccessClose;
1400 p_sessions[i_session_id - 1].p_sys = malloc(sizeof(system_ids_t));
1401 memset( p_sessions[i_session_id - 1].p_sys, 0,
1402 sizeof(system_ids_t) );
1403
1404 APDUSend( p_access, i_session_id, AOT_CA_INFO_ENQ0x9F8030, NULL((void*)0), 0 );
1405}
1406
1407/*
1408 * Date Time
1409 */
1410
1411typedef struct
1412{
1413 int i_interval;
1414 mtime_t i_last;
1415} date_time_t;
1416
1417/*****************************************************************************
1418 * DateTimeSend
1419 *****************************************************************************/
1420static void DateTimeSend( access_t * p_access, int i_session_id )
1421{
1422 date_time_t *p_date =
1423 (date_time_t *)p_sessions[i_session_id - 1].p_sys;
1424
1425 time_t t = time(NULL((void*)0));
1426 struct tm tm_gmt;
1427 struct tm tm_loc;
1428
1429 if ( gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc) )
1430 {
1431 int Y = tm_gmt.tm_year;
1432 int M = tm_gmt.tm_mon + 1;
1433 int D = tm_gmt.tm_mday;
1434 int L = (M == 1 || M == 2) ? 1 : 0;
1435 int MJD = 14956 + D + (int)((Y - L) * 365.25)
1436 + (int)((M + 1 + L * 12) * 30.6001);
1437 uint8_t p_response[7];
1438
1439#define DEC2BCD(d)(((d / 10) << 4) + (d % 10)) (((d / 10) << 4) + (d % 10))
1440
1441 p_response[0] = htons(MJD)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (MJD); if (__builtin_constant_p (__x)) __v = ((unsigned
short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff
) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0"
(__x) : "cc"); __v; }))
>> 8;
1442 p_response[1] = htons(MJD)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (MJD); if (__builtin_constant_p (__x)) __v = ((unsigned
short int) ((((__x) >> 8) & 0xff) | (((__x) & 0xff
) << 8))); else __asm__ ("rorw $8, %w0" : "=r" (__v) : "0"
(__x) : "cc"); __v; }))
& 0xff;
1443 p_response[2] = DEC2BCD(tm_gmt.tm_hour)(((tm_gmt.tm_hour / 10) << 4) + (tm_gmt.tm_hour % 10));
1444 p_response[3] = DEC2BCD(tm_gmt.tm_min)(((tm_gmt.tm_min / 10) << 4) + (tm_gmt.tm_min % 10));
1445 p_response[4] = DEC2BCD(tm_gmt.tm_sec)(((tm_gmt.tm_sec / 10) << 4) + (tm_gmt.tm_sec % 10));
1446 p_response[5] = htons(tm_loc.tm_gmtoff / 60)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (tm_loc.tm_gmtoff / 60); if (__builtin_constant_p (__x)
) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
>> 8;
1447 p_response[6] = htons(tm_loc.tm_gmtoff / 60)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (tm_loc.tm_gmtoff / 60); if (__builtin_constant_p (__x)
) __v = ((unsigned short int) ((((__x) >> 8) & 0xff
) | (((__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0"
: "=r" (__v) : "0" (__x) : "cc"); __v; }))
& 0xff;
1448
1449 APDUSend( p_access, i_session_id, AOT_DATE_TIME0x9F8441, p_response, 7 );
1450
1451 p_date->i_last = i_wallclock;
1452 }
1453}
1454
1455/*****************************************************************************
1456 * DateTimeHandle
1457 *****************************************************************************/
1458static void DateTimeHandle( access_t * p_access, int i_session_id,
1459 uint8_t *p_apdu, int i_size )
1460{
1461 date_time_t *p_date =
1462 (date_time_t *)p_sessions[i_session_id - 1].p_sys;
1463
1464 int i_tag = APDUGetTag( p_apdu, i_size );
1465
1466 switch ( i_tag )
1467 {
1468 case AOT_DATE_TIME_ENQ0x9F8440:
1469 {
1470 int l;
1471 const uint8_t *d = APDUGetLength( p_apdu, &l );
1472
1473 if ( l > 0 )
1474 {
1475 p_date->i_interval = *d;
1476 msg_Dbg( p_access, "DateTimeHandle : interval set to %d",
1477 p_date->i_interval );
1478 }
1479 else
1480 p_date->i_interval = 0;
1481
1482 DateTimeSend( p_access, i_session_id );
1483 break;
1484 }
1485 default:
1486 msg_Err( p_access, "unexpected tag in DateTimeHandle (0x%x)", i_tag );
1487 }
1488}
1489
1490/*****************************************************************************
1491 * DateTimeManage
1492 *****************************************************************************/
1493static void DateTimeManage( access_t * p_access, int i_session_id )
1494{
1495 date_time_t *p_date =
1496 (date_time_t *)p_sessions[i_session_id - 1].p_sys;
1497
1498 if ( p_date->i_interval
1499 && i_wallclock > p_date->i_last + (mtime_t)p_date->i_interval * 1000000 )
1500 {
1501 DateTimeSend( p_access, i_session_id );
1502 }
1503}
1504
1505/*****************************************************************************
1506 * DateTimeClose
1507 *****************************************************************************/
1508static void DateTimeClose( access_t * p_access, int i_session_id )
1509{
1510 msg_Dbg( p_access, "closing DateTime session (%d)", i_session_id );
1511
1512 free( p_sessions[i_session_id - 1].p_sys );
1513}
1514
1515/*****************************************************************************
1516 * DateTimeOpen
1517 *****************************************************************************/
1518static void DateTimeOpen( access_t * p_access, int i_session_id )
1519{
1520 msg_Dbg( p_access, "opening DateTime session (%d)", i_session_id );
1521
1522 p_sessions[i_session_id - 1].pf_handle = DateTimeHandle;
1523 p_sessions[i_session_id - 1].pf_manage = DateTimeManage;
1524 p_sessions[i_session_id - 1].pf_close = DateTimeClose;
1525 p_sessions[i_session_id - 1].p_sys = malloc(sizeof(date_time_t));
1526 memset( p_sessions[i_session_id - 1].p_sys, 0, sizeof(date_time_t) );
1527
1528 DateTimeSend( p_access, i_session_id );
1529}
1530
1531/*
1532 * MMI
1533 */
1534
1535/* Display Control Commands */
1536
1537#define DCC_SET_MMI_MODE0x01 0x01
1538#define DCC_DISPLAY_CHARACTER_TABLE_LIST0x02 0x02
1539#define DCC_INPUT_CHARACTER_TABLE_LIST0x03 0x03
1540#define DCC_OVERLAY_GRAPHICS_CHARACTERISTICS0x04 0x04
1541#define DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS0x05 0x05
1542
1543/* MMI Modes */
1544
1545#define MM_HIGH_LEVEL0x01 0x01
1546#define MM_LOW_LEVEL_OVERLAY_GRAPHICS0x02 0x02
1547#define MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS0x03 0x03
1548
1549/* Display Reply IDs */
1550
1551#define DRI_MMI_MODE_ACK0x01 0x01
1552#define DRI_LIST_DISPLAY_CHARACTER_TABLES0x02 0x02
1553#define DRI_LIST_INPUT_CHARACTER_TABLES0x03 0x03
1554#define DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS0x04 0x04
1555#define DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS0x05 0x05
1556#define DRI_UNKNOWN_DISPLAY_CONTROL_CMD0xF0 0xF0
1557#define DRI_UNKNOWN_MMI_MODE0xF1 0xF1
1558#define DRI_UNKNOWN_CHARACTER_TABLE0xF2 0xF2
1559
1560/* Enquiry Flags */
1561
1562#define EF_BLIND0x01 0x01
1563
1564/* Answer IDs */
1565
1566#define AI_CANCEL0x00 0x00
1567#define AI_ANSWER0x01 0x01
1568
1569typedef struct
1570{
1571 en50221_mmi_object_t last_object;
1572} mmi_t;
1573
1574static inline void en50221_MMIFree( en50221_mmi_object_t *p_object )
1575{
1576 int i;
1577
1578 switch ( p_object->i_object_type )
1579 {
1580 case EN50221_MMI_ENQ1:
1581 free( p_object->u.enq.psz_text );
1582 break;
1583
1584 case EN50221_MMI_ANSW2:
1585 if ( p_object->u.answ.b_ok )
1586 {
1587 free( p_object->u.answ.psz_answ );
1588 }
1589 break;
1590
1591 case EN50221_MMI_MENU3:
1592 case EN50221_MMI_LIST5:
1593 free( p_object->u.menu.psz_title );
1594 free( p_object->u.menu.psz_subtitle );
1595 free( p_object->u.menu.psz_bottom );
1596 for ( i = 0; i < p_object->u.menu.i_choices; i++ )
1597 {
1598 free( p_object->u.menu.ppsz_choices[i] );
1599 }
1600 free( p_object->u.menu.ppsz_choices );
1601 break;
1602
1603 default:
1604 break;
1605 }
1606}
1607
1608/*****************************************************************************
1609 * MMISendObject
1610 *****************************************************************************/
1611static void MMISendObject( access_t *p_access, int i_session_id,
1612 en50221_mmi_object_t *p_object )
1613{
1614 int i_slot = p_sessions[i_session_id - 1].i_slot;
1615 uint8_t *p_data;
1616 int i_size, i_tag;
1617
1618 switch ( p_object->i_object_type )
1619 {
1620 case EN50221_MMI_ANSW2:
1621 i_tag = AOT_ANSW0x9F8808;
1622 i_size = 1 + strlen( p_object->u.answ.psz_answ );
1623 p_data = malloc( i_size );
1624 p_data[0] = (p_object->u.answ.b_ok == true1) ? 0x1 : 0x0;
1625 strncpy( (char *)&p_data[1], p_object->u.answ.psz_answ, i_size - 1 )__builtin_strncpy ((char *)&p_data[1], p_object->u.answ
.psz_answ, i_size - 1)
;
1626 break;
1627
1628 case EN50221_MMI_MENU_ANSW4:
1629 i_tag = AOT_MENU_ANSW0x9F880B;
1630 i_size = 1;
1631 p_data = malloc( i_size );
1632 p_data[0] = p_object->u.menu_answ.i_choice;
1633 break;
1634
1635 default:
1636 msg_Err( p_access, "unknown MMI object %d", p_object->i_object_type );
1637 return;
1638 }
1639
1640 APDUSend( p_access, i_session_id, i_tag, p_data, i_size );
1641 free( p_data );
1642
1643 p_slots[i_slot].b_mmi_expected = true1;
1644}
1645
1646/*****************************************************************************
1647 * MMISendClose
1648 *****************************************************************************/
1649static void MMISendClose( access_t *p_access, int i_session_id )
1650{
1651 int i_slot = p_sessions[i_session_id - 1].i_slot;
1652
1653 APDUSend( p_access, i_session_id, AOT_CLOSE_MMI0x9F8800, NULL((void*)0), 0 );
1654
1655 p_slots[i_slot].b_mmi_expected = true1;
1656}
1657
1658/*****************************************************************************
1659 * MMIDisplayReply
1660 *****************************************************************************/
1661static void MMIDisplayReply( access_t *p_access, int i_session_id )
1662{
1663 uint8_t p_response[2];
1664
1665 p_response[0] = DRI_MMI_MODE_ACK0x01;
1666 p_response[1] = MM_HIGH_LEVEL0x01;
1667
1668 APDUSend( p_access, i_session_id, AOT_DISPLAY_REPLY0x9F8802, p_response, 2 );
1669
1670 msg_Dbg( p_access, "sending DisplayReply on session (%d)", i_session_id );
1671}
1672
1673/*****************************************************************************
1674 * MMIGetText
1675 *****************************************************************************/
1676static char *MMIGetText( access_t *p_access, uint8_t **pp_apdu, int *pi_size )
1677{
1678 int i_tag = APDUGetTag( *pp_apdu, *pi_size );
1679 int l;
1680 uint8_t *d;
1681
1682 if ( i_tag != AOT_TEXT_LAST0x9F8803 )
1683 {
1684 msg_Err( p_access, "unexpected text tag: %06x", i_tag );
1685 *pi_size = 0;
1686 return strdup( "" )(__extension__ (__builtin_constant_p ("") && ((size_t
)(const void *)(("") + 1) - (size_t)(const void *)("") == 1) ?
(((const char *) (""))[0] == '\0' ? (char *) calloc ((size_t
) 1, (size_t) 1) : ({ size_t __len = strlen ("") + 1; char *__retval
= (char *) malloc (__len); if (__retval != ((void*)0)) __retval
= (char *) memcpy (__retval, "", __len); __retval; })) : __strdup
("")))
;
1687 }
1688
1689 d = APDUGetLength( *pp_apdu, &l );
1690
1691 *pp_apdu += l + 4;
1692 *pi_size -= l + 4;
1693
1694 return dvb_string_get( d, l, demux_Iconv, p_access );
1695}
1696
1697/*****************************************************************************
1698 * MMIHandleEnq
1699 *****************************************************************************/
1700static void MMIHandleEnq( access_t *p_access, int i_session_id,
1701 uint8_t *p_apdu, int i_size )
1702{
1703 mmi_t *p_mmi = (mmi_t *)p_sessions[i_session_id - 1].p_sys;
1704 int i_slot = p_sessions[i_session_id - 1].i_slot;
1705 int l;
1706 uint8_t *d = APDUGetLength( p_apdu, &l );
1707
1708 en50221_MMIFree( &p_mmi->last_object );
1709 p_mmi->last_object.i_object_type = EN50221_MMI_ENQ1;
1710 p_mmi->last_object.u.enq.b_blind = (*d & 0x1) ? true1 : false0;
1711 d += 2; /* skip answer_text_length because it is not mandatory */
1712 l -= 2;
1713 p_mmi->last_object.u.enq.psz_text = malloc( l + 1 );
1714 strncpy( p_mmi->last_object.u.enq.psz_text, (char *)d, l )__builtin_strncpy (p_mmi->last_object.u.enq.psz_text, (char
*)d, l)
;
1715 p_mmi->last_object.u.enq.psz_text[l] = '\0';
1716
1717 msg_Dbg( p_access, "MMI enq: %s%s", p_mmi->last_object.u.enq.psz_text,
1718 p_mmi->last_object.u.enq.b_blind == true1 ? " (blind)" : "" );
1719
1720 p_slots[i_slot].b_mmi_expected = false0;
1721 p_slots[i_slot].b_mmi_undisplayed = true1;
1722}
1723
1724/*****************************************************************************
1725 * MMIHandleMenu
1726 *****************************************************************************/
1727static void MMIHandleMenu( access_t *p_access, int i_session_id, int i_tag,
1728 uint8_t *p_apdu, int i_size )
1729{
1730 mmi_t *p_mmi = (mmi_t *)p_sessions[i_session_id - 1].p_sys;
1731 int i_slot = p_sessions[i_session_id - 1].i_slot;
1732 int l;
1733 uint8_t *d = APDUGetLength( p_apdu, &l );
1734
1735 en50221_MMIFree( &p_mmi->last_object );
1736 p_mmi->last_object.i_object_type = (i_tag == AOT_MENU_LAST0x9F8809) ?
1737 EN50221_MMI_MENU3 : EN50221_MMI_LIST5;
1738 p_mmi->last_object.u.menu.i_choices = 0;
1739 p_mmi->last_object.u.menu.ppsz_choices = NULL((void*)0);
1740
1741 if ( l > 0 )
1742 {
1743 l--; d++; /* choice_nb */
1744
1745#define GET_FIELD( x ) \
1746 if ( l > 0 ) \
1747 { \
1748 p_mmi->last_object.u.menu.psz_##x \
1749 = MMIGetText( p_access, &d, &l ); \
1750 msg_Dbg( p_access, "MMI " STRINGIFY( x )"x" ": %s", \
1751 p_mmi->last_object.u.menu.psz_##x ); \
1752 }
1753
1754 GET_FIELD( title );
1755 GET_FIELD( subtitle );
1756 GET_FIELD( bottom );
1757#undef GET_FIELD
1758
1759 while ( l > 0 )
1760 {
1761 char *psz_text = MMIGetText( p_access, &d, &l );
1762 TAB_APPEND( p_mmi->last_object.u.menu.i_choices,if( (p_mmi->last_object.u.menu.i_choices) > 0 ) { (p_mmi
->last_object.u.menu.ppsz_choices) = realloc( p_mmi->last_object
.u.menu.ppsz_choices, sizeof( void ** ) * ( (p_mmi->last_object
.u.menu.i_choices) + 1 ) ); } else { (p_mmi->last_object.u
.menu.ppsz_choices) = malloc( sizeof( void ** ) ); } (p_mmi->
last_object.u.menu.ppsz_choices)[p_mmi->last_object.u.menu
.i_choices] = (psz_text); (p_mmi->last_object.u.menu.i_choices
)++
Result of 'malloc' is converted to a pointer of type 'char *', which is incompatible with sizeof operand type 'void **'
1763 p_mmi->last_object.u.menu.ppsz_choices,if( (p_mmi->last_object.u.menu.i_choices) > 0 ) { (p_mmi
->last_object.u.menu.ppsz_choices) = realloc( p_mmi->last_object
.u.menu.ppsz_choices, sizeof( void ** ) * ( (p_mmi->last_object
.u.menu.i_choices) + 1 ) ); } else { (p_mmi->last_object.u
.menu.ppsz_choices) = malloc( sizeof( void ** ) ); } (p_mmi->
last_object.u.menu.ppsz_choices)[p_mmi->last_object.u.menu
.i_choices] = (psz_text); (p_mmi->last_object.u.menu.i_choices
)++
1764 psz_text )if( (p_mmi->last_object.u.menu.i_choices) > 0 ) { (p_mmi
->last_object.u.menu.ppsz_choices) = realloc( p_mmi->last_object
.u.menu.ppsz_choices, sizeof( void ** ) * ( (p_mmi->last_object
.u.menu.i_choices) + 1 ) ); } else { (p_mmi->last_object.u
.menu.ppsz_choices) = malloc( sizeof( void ** ) ); } (p_mmi->
last_object.u.menu.ppsz_choices)[p_mmi->last_object.u.menu
.i_choices] = (psz_text); (p_mmi->last_object.u.menu.i_choices
)++
;
1765 msg_Dbg( p_access, "MMI choice: %s", psz_text );
1766 }
1767 }
1768
1769 p_slots[i_slot].b_mmi_expected = false0;
1770 p_slots[i_slot].b_mmi_undisplayed = true1;
1771}
1772
1773/*****************************************************************************
1774 * MMIHandle
1775 *****************************************************************************/
1776static void MMIHandle( access_t *p_access, int i_session_id,
1777 uint8_t *p_apdu, int i_size )
1778{
1779 int i_tag = APDUGetTag( p_apdu, i_size );
1780
1781 switch ( i_tag )
1782 {
1783 case AOT_DISPLAY_CONTROL0x9F8801:
1784 {
1785 int l;
1786 uint8_t *d = APDUGetLength( p_apdu, &l );
1787
1788 if ( l > 0 )
1789 {
1790 switch ( *d )
1791 {
1792 case DCC_SET_MMI_MODE0x01:
1793 if ( l == 2 && d[1] == MM_HIGH_LEVEL0x01 )
1794 MMIDisplayReply( p_access, i_session_id );
1795 else
1796 msg_Err( p_access, "unsupported MMI mode %02x", d[1] );
1797 break;
1798
1799 default:
1800 msg_Err( p_access, "unsupported display control command %02x",
1801 *d );
1802 break;
1803 }
1804 }
1805 break;
1806 }
1807
1808 case AOT_ENQ0x9F8807:
1809 MMIHandleEnq( p_access, i_session_id, p_apdu, i_size );
1810 break;
1811
1812 case AOT_LIST_LAST0x9F880C:
1813 case AOT_MENU_LAST0x9F8809:
1814 MMIHandleMenu( p_access, i_session_id, i_tag, p_apdu, i_size );
1815 break;
1816
1817 case AOT_CLOSE_MMI0x9F8800:
1818 SessionSendClose( p_access, i_session_id );
1819 break;
1820
1821 default:
1822 msg_Err( p_access, "unexpected tag in MMIHandle (0x%x)", i_tag );
1823 }
1824}
1825
1826/*****************************************************************************
1827 * MMIClose
1828 *****************************************************************************/
1829static void MMIClose( access_t *p_access, int i_session_id )
1830{
1831 int i_slot = p_sessions[i_session_id - 1].i_slot;
1832 mmi_t *p_mmi = (mmi_t *)p_sessions[i_session_id - 1].p_sys;
1833
1834 en50221_MMIFree( &p_mmi->last_object );
1835 free( p_sessions[i_session_id - 1].p_sys );
1836
1837 msg_Dbg( p_access, "closing MMI session (%d)", i_session_id );
1838
1839 p_slots[i_slot].b_mmi_expected = false0;
1840 p_slots[i_slot].b_mmi_undisplayed = true1;
1841}
1842
1843/*****************************************************************************
1844 * MMIOpen
1845 *****************************************************************************/
1846static void MMIOpen( access_t *p_access, int i_session_id )
1847{
1848 mmi_t *p_mmi;
1849
1850 msg_Dbg( p_access, "opening MMI session (%d)", i_session_id );
1851
1852 p_sessions[i_session_id - 1].pf_handle = MMIHandle;
1853 p_sessions[i_session_id - 1].pf_close = MMIClose;
1854 p_sessions[i_session_id - 1].p_sys = malloc(sizeof(mmi_t));
1855 p_mmi = (mmi_t *)p_sessions[i_session_id - 1].p_sys;
1856 p_mmi->last_object.i_object_type = EN50221_MMI_NONE0;
1857}
1858
1859
1860/*
1861 * Hardware handling
1862 */
1863
1864/*****************************************************************************
1865 * InitSlot: Open the transport layer
1866 *****************************************************************************/
1867static void InitSlot( access_t * p_access, int i_slot )
1868{
1869 if ( TPDUSend( p_access, i_slot, T_CREATE_TC0x82, NULL((void*)0), 0 ) != 0 )
1870 msg_Err( p_access, "en50221_Init: couldn't send TPDU on slot %d",
1871 i_slot );
1872}
1873
1874/*****************************************************************************
1875 * ResetSlot
1876 *****************************************************************************/
1877static void ResetSlot( int i_slot )
1878{
1879 ci_slot_t *p_slot = &p_slots[i_slot];
1880 int i_session_id;
1881
1882 switch (i_print_type)
1883 {
1884 case PRINT_XML:
1885 printf("<STATUS type=\"cam\" status=\"0\" />\n");
1886 break;
1887 default:
1888 break;
1889 }
1890
1891 if ( ioctl( i_ca_handle, CA_RESET(((0U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((128)) << 0) | ((0) << ((0 +8)+8)))
, 1 << i_slot ) != 0 )
1892 msg_Err( NULL((void*)0), "en50221_Poll: couldn't reset slot %d", i_slot );
1893 p_slot->b_active = false0;
1894 p_slot->i_init_timeout = mdate() + CAM_INIT_TIMEOUT15000000;
1895 p_slot->b_expect_answer = false0;
1896 p_slot->b_mmi_expected = false0;
1897 p_slot->b_mmi_undisplayed = false0;
1898 if ( p_slot->p_recv != NULL((void*)0) )
1899 {
1900 free( p_slot->p_recv->p_data );
1901 free( p_slot->p_recv );
1902 }
1903 p_slot->p_recv = NULL((void*)0);
1904 while ( p_slot->p_send != NULL((void*)0) )
1905 {
1906 en50221_msg_t *p_next = p_slot->p_send->p_next;
1907 free( p_slot->p_send->p_data );
1908 free( p_slot->p_send );
1909 p_slot->p_send = p_next;
1910 }
1911 p_slot->pp_send_last = &p_slot->p_send;
1912
1913 /* Close all sessions for this slot. */
1914 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
1915 {
1916 if ( p_sessions[i_session_id - 1].i_resource_id
1917 && p_sessions[i_session_id - 1].i_slot == i_slot )
1918 {
1919 if ( p_sessions[i_session_id - 1].pf_close != NULL((void*)0) )
1920 {
1921 p_sessions[i_session_id - 1].pf_close( NULL((void*)0), i_session_id );
1922 }
1923 p_sessions[i_session_id - 1].i_resource_id = 0;
1924 }
1925 }
1926}
1927
1928
1929/*
1930 * External entry points
1931 */
1932
1933/*****************************************************************************
1934 * en50221_Init : Initialize the CAM for en50221
1935 *****************************************************************************/
1936void en50221_Init( void )
1937{
1938 char psz_tmp[128];
1939 ca_caps_t caps;
1940
1941 memset( &caps, 0, sizeof( ca_caps_t ));
1942
1943 sprintf( psz_tmp, "/dev/dvb/adapter%d/ca%d", i_adapter, i_canum );
1944 if( (i_ca_handle = open(psz_tmp, O_RDWR02 | O_NONBLOCK04000)) < 0 )
1945 {
1946 msg_Warn( NULL((void*)0), "failed opening CAM device %s (%s)",
1947 psz_tmp, strerror(errno(*__errno_location ())) );
1948 i_ca_handle = 0;
1949 return;
1950 }
1951
1952 if ( ioctl( i_ca_handle, CA_GET_CAP(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((129)) << 0) | ((((sizeof(ca_caps_t)))) << ((0
+8)+8)))
, &caps ) != 0 )
1953 {
1954 msg_Err( NULL((void*)0), "failed getting CAM capabilities (%s)",
1955 strerror(errno(*__errno_location ())) );
1956 close( i_ca_handle );
1957 i_ca_handle = 0;
1958 return;
1959 }
1960
1961 /* Output CA capabilities */
1962 msg_Dbg( NULL((void*)0), "CA interface with %d %s", caps.slot_num,
1963 caps.slot_num == 1 ? "slot" : "slots" );
1964 if ( caps.slot_type & CA_CI1 )
1965 msg_Dbg( NULL((void*)0), " CI high level interface type" );
1966 if ( caps.slot_type & CA_CI_LINK2 )
1967 msg_Dbg( NULL((void*)0), " CI link layer level interface type" );
1968 if ( caps.slot_type & CA_CI_PHYS4 )
1969 msg_Dbg( NULL((void*)0), " CI physical layer level interface type (not supported) " );
1970 if ( caps.slot_type & CA_DESCR8 )
1971 msg_Dbg( NULL((void*)0), " built-in descrambler detected" );
1972 if ( caps.slot_type & CA_SC128 )
1973 msg_Dbg( NULL((void*)0), " simple smart card interface" );
1974
1975 msg_Dbg( NULL((void*)0), " %d available %s", caps.descr_num,
1976 caps.descr_num == 1 ? "descrambler (key)" : "descramblers (keys)" );
1977 if ( caps.descr_type & CA_ECD1 )
1978 msg_Dbg( NULL((void*)0), " ECD scrambling system supported" );
1979 if ( caps.descr_type & CA_NDS2 )
1980 msg_Dbg( NULL((void*)0), " NDS scrambling system supported" );
1981 if ( caps.descr_type & CA_DSS4 )
1982 msg_Dbg( NULL((void*)0), " DSS scrambling system supported" );
1983
1984 if ( caps.slot_num == 0 )
1985 {
1986 msg_Err( NULL((void*)0), "CAM module with no slots" );
1987 close( i_ca_handle );
1988 i_ca_handle = 0;
1989 return;
1990 }
1991
1992 if( caps.slot_type & CA_CI_LINK2 )
1993 i_ca_type = CA_CI_LINK2;
1994 else if( caps.slot_type & CA_CI1 )
1995 i_ca_type = CA_CI1;
1996 else
1997 {
1998 msg_Err( NULL((void*)0), "Incompatible CAM interface" );
1999 close( i_ca_handle );
2000 i_ca_handle = 0;
2001 return;
2002 }
2003
2004 i_nb_slots = caps.slot_num;
2005 memset( p_sessions, 0, sizeof(en50221_session_t) * MAX_SESSIONS32 );
2006
2007 en50221_Reset();
2008}
2009
2010/*****************************************************************************
2011 * en50221_Reset : Reset the CAM for en50221
2012 *****************************************************************************/
2013void en50221_Reset( void )
2014{
2015 memset( p_slots, 0, sizeof(ci_slot_t) * MAX_CI_SLOTS16 );
2016
2017 if( i_ca_type & CA_CI_LINK2 )
2018 {
2019 int i_slot;
2020 for ( i_slot = 0; i_slot < i_nb_slots; i_slot++ )
2021 ResetSlot( i_slot );
2022 }
2023 else
2024 {
2025 struct ca_slot_info info;
2026 system_ids_t *p_ids;
2027 ca_msg_t ca_msg;
2028 info.num = 0;
2029
2030 /* We don't reset the CAM in that case because it's done by the
2031 * ASIC. */
2032 if ( ioctl( i_ca_handle, CA_GET_SLOT_INFO(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((130)) << 0) | ((((sizeof(ca_slot_info_t)))) <<
((0 +8)+8)))
, &info ) < 0 )
2033 {
2034 msg_Err( NULL((void*)0), "en50221_Init: couldn't get slot info" );
2035 close( i_ca_handle );
2036 i_ca_handle = 0;
2037 return;
2038 }
2039 if( info.flags == 0 )
2040 {
2041 msg_Err( NULL((void*)0), "en50221_Init: no CAM inserted" );
2042 close( i_ca_handle );
2043 i_ca_handle = 0;
2044 return;
2045 }
2046
2047 /* Allocate a dummy sessions */
2048 p_sessions[0].i_resource_id = RI_CONDITIONAL_ACCESS_SUPPORT0x00030041;
2049 p_sessions[0].pf_close = ConditionalAccessClose;
2050 if ( p_sessions[0].p_sys == NULL((void*)0) )
2051 p_sessions[0].p_sys = malloc(sizeof(system_ids_t));
2052 memset( p_sessions[0].p_sys, 0, sizeof(system_ids_t) );
2053 p_ids = (system_ids_t *)p_sessions[0].p_sys;
2054 p_ids->b_high_level = 1;
2055
2056 /* Get application info to find out which cam we are using and make
2057 sure everything is ready to play */
2058 ca_msg.length=3;
2059 ca_msg.msg[0] = ( AOT_APPLICATION_INFO0x9F8021 & 0xFF0000 ) >> 16;
2060 ca_msg.msg[1] = ( AOT_APPLICATION_INFO0x9F8021 & 0x00FF00 ) >> 8;
2061 ca_msg.msg[2] = ( AOT_APPLICATION_INFO0x9F8021 & 0x0000FF ) >> 0;
2062 memset( &ca_msg.msg[3], 0, 253 );
2063 APDUSend( NULL((void*)0), 1, AOT_APPLICATION_INFO_ENQ0x9F8020, NULL((void*)0), 0 );
2064 if ( ioctl( i_ca_handle, CA_GET_MSG(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((132)) << 0) | ((((sizeof(ca_msg_t)))) << ((0 +
8)+8)))
, &ca_msg ) < 0 )
2065 {
2066 msg_Err( NULL((void*)0), "en50221_Init: failed getting message" );
2067 close( i_ca_handle );
2068 i_ca_handle = 0;
2069 return;
2070 }
2071
2072#ifdef HLCI_WAIT_CAM_READY
2073 while( ca_msg.msg[8] == 0xff && ca_msg.msg[9] == 0xff )
2074 {
2075 msleep(1);
2076 msg_Dbg( NULL((void*)0), "CAM: please wait" );
2077 APDUSend( NULL((void*)0), 1, AOT_APPLICATION_INFO_ENQ0x9F8020, NULL((void*)0), 0 );
2078 ca_msg.length=3;
2079 ca_msg.msg[0] = ( AOT_APPLICATION_INFO0x9F8021 & 0xFF0000 ) >> 16;
2080 ca_msg.msg[1] = ( AOT_APPLICATION_INFO0x9F8021 & 0x00FF00 ) >> 8;
2081 ca_msg.msg[2] = ( AOT_APPLICATION_INFO0x9F8021 & 0x0000FF ) >> 0;
2082 memset( &ca_msg.msg[3], 0, 253 );
2083 if ( ioctl( i_ca_handle, CA_GET_MSG(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((132)) << 0) | ((((sizeof(ca_msg_t)))) << ((0 +
8)+8)))
, &ca_msg ) < 0 )
2084 {
2085 msg_Err( NULL((void*)0), "en50221_Init: failed getting message" );
2086 close( i_ca_handle );
2087 i_ca_handle = 0;
2088 return;
2089 }
2090 msg_Dbg( NULL((void*)0), "en50221_Init: Got length: %d, tag: 0x%x", ca_msg.length, APDUGetTag( ca_msg.msg, ca_msg.length ) );
2091 }
2092#else
2093 if( ca_msg.msg[8] == 0xff && ca_msg.msg[9] == 0xff )
2094 {
2095 msg_Err( NULL((void*)0), "CAM returns garbage as application info!" );
2096 close( i_ca_handle );
2097 i_ca_handle = 0;
2098 return;
2099 }
2100#endif
2101 msg_Dbg( NULL((void*)0), "found CAM %s using id 0x%x", &ca_msg.msg[12],
2102 (ca_msg.msg[8]<<8)|ca_msg.msg[9] );
2103 }
2104}
2105
2106/*****************************************************************************
2107 * en50221_Read : Read the CAM for a TPDU
2108 *****************************************************************************/
2109void en50221_Read( void )
2110{
2111 TPDURecv( NULL((void*)0) );
2112}
2113
2114/*****************************************************************************
2115 * en50221_Poll : Send a poll TPDU to the CAM
2116 *****************************************************************************/
2117void en50221_Poll( void )
2118{
2119 int i_slot;
2120 int i_session_id;
2121
2122 /* Check module status */
2123 for ( i_slot = 0; i_slot < i_nb_slots; i_slot++ )
2124 {
2125 ci_slot_t *p_slot = &p_slots[i_slot];
2126 ca_slot_info_t sinfo;
2127
2128 sinfo.num = i_slot;
2129 if ( ioctl( i_ca_handle, CA_GET_SLOT_INFO(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((130)) << 0) | ((((sizeof(ca_slot_info_t)))) <<
((0 +8)+8)))
, &sinfo ) != 0 )
2130 {
2131 msg_Err( NULL((void*)0), "en50221_Poll: couldn't get info on slot %d",
2132 i_slot );
2133 continue;
2134 }
2135
2136 if ( !(sinfo.flags & CA_CI_MODULE_READY2) )
2137 {
2138 if ( p_slot->b_active )
2139 {
2140 msg_Dbg( NULL((void*)0), "en50221_Poll: slot %d has been removed",
2141 i_slot );
2142 ResetSlot( i_slot );
2143 }
2144
2145 continue;
2146 }
2147 else if ( !p_slot->b_active )
2148 {
2149 if ( !p_slot->b_expect_answer )
2150 InitSlot( NULL((void*)0), i_slot );
2151 else if ( p_slot->i_init_timeout < i_wallclock )
2152 {
2153 switch (i_print_type) {
2154 case PRINT_XML:
2155 printf("<EVENT type=\"reset\" cause=\"cam_mute\" />\n");
2156 break;
2157 default:
2158 msg_Warn( NULL((void*)0), "no answer from CAM, resetting slot %d",
2159 i_slot );
2160 }
2161 ResetSlot( i_slot );
2162 continue;
2163 }
2164 }
2165 }
2166
2167 /* Check if applications have data to send */
2168 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2169 {
2170 en50221_session_t *p_session = &p_sessions[i_session_id - 1];
2171 if ( p_session->i_resource_id && p_session->pf_manage != NULL((void*)0)
2172 && !p_slots[ p_session->i_slot ].b_expect_answer )
2173 p_session->pf_manage( NULL((void*)0), i_session_id );
2174 }
2175
2176 /* Now send the poll command to inactive slots */
2177 for ( i_slot = 0; i_slot < i_nb_slots; i_slot++ )
2178 {
2179 ci_slot_t *p_slot = &p_slots[i_slot];
2180
2181 if ( p_slot->b_active && !p_slot->b_expect_answer )
2182 {
2183 if ( TPDUSend( NULL((void*)0), i_slot, T_DATA_LAST0xA0, NULL((void*)0), 0 ) != 0 )
2184 {
2185 switch (i_print_type) {
2186 case PRINT_XML:
2187 printf("<EVENT type=\"reset\" cause=\"cam_error\" />\n");
2188 break;
2189 default:
2190 msg_Warn( NULL((void*)0), "couldn't send TPDU, resetting slot %d",
2191 i_slot );
2192 }
2193 ResetSlot( i_slot );
2194 }
2195 }
2196 }
2197}
2198
2199/*****************************************************************************
2200 * en50221_AddPMT :
2201 *****************************************************************************/
2202void en50221_AddPMT( uint8_t *p_pmt )
2203{
2204 int i_session_id;
2205
2206 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2207 if ( p_sessions[i_session_id - 1].i_resource_id
2208 == RI_CONDITIONAL_ACCESS_SUPPORT0x00030041 )
2209 CAPMTAdd( NULL((void*)0), i_session_id, p_pmt );
2210}
2211
2212/*****************************************************************************
2213 * en50221_UpdatePMT :
2214 *****************************************************************************/
2215void en50221_UpdatePMT( uint8_t *p_pmt )
2216{
2217 int i_session_id;
2218
2219 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2220 if ( p_sessions[i_session_id - 1].i_resource_id
2221 == RI_CONDITIONAL_ACCESS_SUPPORT0x00030041 )
2222 CAPMTUpdate( NULL((void*)0), i_session_id, p_pmt );
2223}
2224
2225/*****************************************************************************
2226 * en50221_DeletePMT :
2227 *****************************************************************************/
2228void en50221_DeletePMT( uint8_t *p_pmt )
2229{
2230 int i_session_id;
2231
2232 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2233 if ( p_sessions[i_session_id - 1].i_resource_id
2234 == RI_CONDITIONAL_ACCESS_SUPPORT0x00030041 )
2235 CAPMTDelete( NULL((void*)0), i_session_id, p_pmt );
2236}
2237
2238/*****************************************************************************
2239 * en50221_StatusMMI :
2240 *****************************************************************************/
2241uint8_t en50221_StatusMMI( uint8_t *p_answer, ssize_t *pi_size )
2242{
2243 struct ret_mmi_status *p_ret = (struct ret_mmi_status *)p_answer;
2244
2245 if ( ioctl( i_ca_handle, CA_GET_CAP(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((129)) << 0) | ((((sizeof(ca_caps_t)))) << ((0
+8)+8)))
, &p_ret->caps ) != 0 )
2246 {
2247 msg_Err( NULL((void*)0), "ioctl CA_GET_CAP failed (%s)", strerror(errno(*__errno_location ())) );
2248 return RET_ERR;
2249 }
2250
2251 *pi_size = sizeof(struct ret_mmi_status);
2252 return RET_MMI_STATUS;
2253}
2254
2255/*****************************************************************************
2256 * en50221_StatusMMISlot :
2257 *****************************************************************************/
2258uint8_t en50221_StatusMMISlot( uint8_t *p_buffer, ssize_t i_size,
2259 uint8_t *p_answer, ssize_t *pi_size )
2260{
2261 int i_slot;
2262 struct ret_mmi_slot_status *p_ret = (struct ret_mmi_slot_status *)p_answer;
2263
2264 if ( i_size != 1 ) return RET_HUH;
2265 i_slot = *p_buffer;
2266
2267 p_ret->sinfo.num = i_slot;
2268 if ( ioctl( i_ca_handle, CA_GET_SLOT_INFO(((2U) << (((0 +8)+8)+14)) | ((('o')) << (0 +8)) |
(((130)) << 0) | ((((sizeof(ca_slot_info_t)))) <<
((0 +8)+8)))
, &p_ret->sinfo ) != 0 )
2269 {
2270 msg_Err( NULL((void*)0), "ioctl CA_GET_SLOT_INFO failed (%s)", strerror(errno(*__errno_location ())) );
2271 return RET_ERR;
2272 }
2273
2274 *pi_size = sizeof(struct ret_mmi_slot_status);
2275 return RET_MMI_SLOT_STATUS;
2276}
2277
2278/*****************************************************************************
2279 * en50221_OpenMMI :
2280 *****************************************************************************/
2281uint8_t en50221_OpenMMI( uint8_t *p_buffer, ssize_t i_size )
2282{
2283 int i_slot;
2284
2285 if ( i_size != 1 ) return RET_HUH;
2286 i_slot = *p_buffer;
2287
2288 if( i_ca_type & CA_CI_LINK2 )
2289 {
2290 int i_session_id;
2291 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2292 {
2293 if ( p_sessions[i_session_id - 1].i_resource_id == RI_MMI0x00400041
2294 && p_sessions[i_session_id - 1].i_slot == i_slot )
2295 {
2296 msg_Dbg( NULL((void*)0),
2297 "MMI menu is already opened on slot %d (session=%d)",
2298 i_slot, i_session_id );
2299 return RET_OK;
2300 }
2301 }
2302
2303 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2304 {
2305 if ( p_sessions[i_session_id - 1].i_resource_id
2306 == RI_APPLICATION_INFORMATION0x00020041
2307 && p_sessions[i_session_id - 1].i_slot == i_slot )
2308 {
2309 ApplicationInformationEnterMenu( NULL((void*)0), i_session_id );
2310 return RET_OK;
2311 }
2312 }
2313
2314 msg_Err( NULL((void*)0), "no application information on slot %d", i_slot );
2315 return RET_ERR;
2316 }
2317 else
2318 {
2319 msg_Err( NULL((void*)0), "MMI menu not supported" );
2320 return RET_ERR;
2321 }
2322}
2323
2324/*****************************************************************************
2325 * en50221_CloseMMI :
2326 *****************************************************************************/
2327uint8_t en50221_CloseMMI( uint8_t *p_buffer, ssize_t i_size )
2328{
2329 int i_slot;
2330
2331 if ( i_size != 1 ) return RET_HUH;
2332 i_slot = *p_buffer;
2333
2334 if( i_ca_type & CA_CI_LINK2 )
2335 {
2336 int i_session_id;
2337 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2338 {
2339 if ( p_sessions[i_session_id - 1].i_resource_id == RI_MMI0x00400041
2340 && p_sessions[i_session_id - 1].i_slot == i_slot )
2341 {
2342 MMISendClose( NULL((void*)0), i_session_id );
2343 return RET_OK;
2344 }
2345 }
2346
2347 msg_Warn( NULL((void*)0), "closing a non-existing MMI session on slot %d",
2348 i_slot );
2349 return RET_ERR;
2350 }
2351 else
2352 {
2353 msg_Err( NULL((void*)0), "MMI menu not supported" );
2354 return RET_ERR;
2355 }
2356}
2357
2358/*****************************************************************************
2359 * en50221_GetMMIObject :
2360 *****************************************************************************/
2361uint8_t en50221_GetMMIObject( uint8_t *p_buffer, ssize_t i_size,
2362 uint8_t *p_answer, ssize_t *pi_size )
2363{
2364 int i_session_id, i_slot;
2365 struct ret_mmi_recv *p_ret = (struct ret_mmi_recv *)p_answer;
2366
2367 if ( i_size != 1 ) return RET_HUH;
2368 i_slot = *p_buffer;
2369
2370 if ( p_slots[i_slot].b_mmi_expected )
2371 return RET_MMI_WAIT; /* data not yet available */
2372
2373 p_ret->object.i_object_type = EN50221_MMI_NONE0;
2374 *pi_size = sizeof(struct ret_mmi_recv);
2375
2376 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2377 {
2378 if ( p_sessions[i_session_id - 1].i_resource_id == RI_MMI0x00400041
2379 && p_sessions[i_session_id - 1].i_slot == i_slot )
2380 {
2381 mmi_t *p_mmi =
2382 (mmi_t *)p_sessions[i_session_id - 1].p_sys;
2383 if ( p_mmi == NULL((void*)0) )
2384 {
2385 *pi_size = 0;
2386 return RET_ERR; /* should not happen */
2387 }
2388
2389 *pi_size = COMM_BUFFER_SIZE(8 + ((4093 + 3) * (256 / 2))) - COMM_HEADER_SIZE8 -
2390 ((void *)&p_ret->object - (void *)p_ret);
2391 if ( en50221_SerializeMMIObject( (uint8_t *)&p_ret->object,
2392 pi_size, &p_mmi->last_object ) == -1 )
2393 {
2394 *pi_size = 0;
2395 msg_Err( NULL((void*)0), "MMI structure too big" );
2396 return RET_ERR;
2397 }
2398 *pi_size += ((void *)&p_ret->object - (void *)p_ret);
2399 break;
2400 }
2401 }
2402
2403 return RET_MMI_RECV;
2404}
2405
2406
2407/*****************************************************************************
2408 * en50221_SendMMIObject :
2409 *****************************************************************************/
2410uint8_t en50221_SendMMIObject( uint8_t *p_buffer, ssize_t i_size )
2411{
2412 int i_session_id, i_slot;
2413 struct cmd_mmi_send *p_cmd = (struct cmd_mmi_send *)p_buffer;
2414
2415 if ( i_size < sizeof(struct cmd_mmi_send))
2416 {
2417 msg_Err( NULL((void*)0), "command packet too short (%zd)\n", i_size );
2418 return RET_HUH;
2419 }
2420
2421 if ( en50221_UnserializeMMIObject( &p_cmd->object, i_size -
2422 ((void *)&p_cmd->object - (void *)p_cmd) ) == -1 )
2423 return RET_ERR;
2424
2425 i_slot = p_cmd->i_slot;
2426
2427 for ( i_session_id = 1; i_session_id <= MAX_SESSIONS32; i_session_id++ )
2428 {
2429 if ( p_sessions[i_session_id - 1].i_resource_id == RI_MMI0x00400041
2430 && p_sessions[i_session_id - 1].i_slot == i_slot )
2431 {
2432 MMISendObject( NULL((void*)0), i_session_id, &p_cmd->object );
2433 return RET_OK;
2434 }
2435 }
2436
2437 msg_Err( NULL((void*)0), "SendMMIObject when no MMI session is opened !" );
2438 return RET_ERR;
2439}
2440
2441#else
2442#include <inttypes.h>
2443
2444int i_ca_handle = 0;
2445int i_ca_type = -1;
2446
2447void en50221_AddPMT( uint8_t *p_pmt ) { };
2448void en50221_UpdatePMT( uint8_t *p_pmt ) { };
2449void en50221_DeletePMT( uint8_t *p_pmt ) { };
2450void en50221_Reset( void ) { };
2451#endif