1 #define MODULE_LOG_PREFIX "dvbazbox"
5 #if defined(HAVE_DVBAPI) && defined(WITH_AZBOX)
7 #include "extapi/openxcas/openxcas_api.h"
8 #include "extapi/openxcas/openxcas_message.h"
10 #include "module-dvbapi.h"
11 #include "module-dvbapi-azbox.h"
12 #include "oscam-client.h"
13 #include "oscam-ecm.h"
14 #include "oscam-reader.h"
15 #include "oscam-string.h"
16 #include "oscam-time.h"
18 // These variables are declared in module-dvbapi.c
19 extern void *dvbapi_client
;
20 extern DEMUXTYPE demux
[MAX_DEMUX
];
22 // These are used in module-dvbapi.c
23 int32_t openxcas_provid
;
24 uint16_t openxcas_sid
, openxcas_caid
, openxcas_ecm_pid
;
26 static uint8_t openxcas_cw
[16];
27 static int32_t openxcas_seq
, openxcas_filter_idx
, openxcas_stream_id
, openxcas_cipher_idx
, openxcas_busy
= 0;
28 static uint16_t openxcas_video_pid
, openxcas_audio_pid
, openxcas_data_pid
;
30 static void azbox_openxcas_ecm_callback(int32_t stream_id
, uint32_t UNUSED(seq
), int32_t cipher_index
, uint32_t UNUSED(caid
), uint8_t *ecm_data
, int32_t l
, uint16_t pid
)
32 cs_log_dbg(D_DVBAPI
, "ecm callback received");
34 openxcas_stream_id
= stream_id
;
36 //openxcas_caid = caid;
37 openxcas_ecm_pid
= pid
;
40 if(l
< 0 || l
> MAX_ECM_SIZE
)
44 if(!(er
= get_ecmtask()))
47 er
->srvid
= openxcas_sid
;
48 er
->caid
= openxcas_caid
;
49 er
->pid
= openxcas_ecm_pid
;
50 er
->prid
= openxcas_provid
;
53 memcpy(er
->ecm
, ecm_data
, er
->ecmlen
);
55 request_cw(dvbapi_client
, er
, 0, 0);
57 //openxcas_stop_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
58 //openxcas_remove_filter(openxcas_stream_id, OPENXCAS_FILTER_ECM);
60 openxcas_cipher_idx
= cipher_index
;
68 static void azbox_openxcas_ex_callback(int32_t stream_id
, uint32_t seq
, int32_t idx
, uint32_t pid
, uint8_t *ecm_data
, int32_t l
)
70 cs_log_dbg(D_DVBAPI
, "ex callback received");
72 openxcas_stream_id
= stream_id
;
73 openxcas_ecm_pid
= pid
;
74 openxcas_cipher_idx
= idx
; // is this really cipher_idx?
76 if(l
< 0 || l
> MAX_ECM_SIZE
)
80 if(!(er
= get_ecmtask()))
83 er
->srvid
= openxcas_sid
;
84 er
->caid
= openxcas_caid
;
85 er
->pid
= openxcas_ecm_pid
;
86 er
->prid
= openxcas_provid
;
89 memcpy(er
->ecm
, ecm_data
, er
->ecmlen
);
91 request_cw(dvbapi_client
, er
, 0, 0);
93 if(openxcas_stop_filter_ex(stream_id
, seq
, openxcas_filter_idx
) < 0)
94 { cs_log("unable to stop ex filter"); }
96 { cs_log_dbg(D_DVBAPI
, "ex filter stopped"); }
102 memset(&mask
, 0x00, sizeof(mask
));
103 memset(&comp
, 0x00, sizeof(comp
));
106 comp
[0] = ecm_data
[0] ^ 1;
108 if((openxcas_filter_idx
= openxcas_start_filter_ex(stream_id
, seq
, openxcas_ecm_pid
, mask
, comp
, (void *)azbox_openxcas_ex_callback
)) < 0)
109 { cs_log("unable to start ex filter"); }
111 { cs_log_dbg(D_DVBAPI
, "ex filter started, pid = %x", openxcas_ecm_pid
); }
114 static void *azbox_main_thread(void *cli
)
116 struct s_client
*client
= (struct s_client
*) cli
;
117 client
->thread
= pthread_self();
118 SAFE_SETSPECIFIC(getclient
, cli
);
121 struct s_auth
*account
;
123 for(account
= cfg
.account
; account
; account
= account
->next
)
125 if((ok
= is_dvbapi_usr(account
->usr
)))
128 cs_auth_client(client
, ok
? account
: (struct s_auth
*)(-1), "dvbapi");
130 dvbapi_read_priority();
134 while((ret
= openxcas_get_message(&msg
, 0)) >= 0)
140 openxcas_stream_id
= msg
.stream_id
;
141 openxcas_seq
= msg
.sequence
;
142 struct stOpenXCAS_Data data
;
146 case OPENXCAS_SELECT_CHANNEL
:
147 cs_log_dbg(D_DVBAPI
, "OPENXCAS_SELECT_CHANNEL");
149 // parse channel info
150 struct stOpenXCASChannel chan
;
151 memcpy(&chan
, msg
.buf
, msg
.buf_len
);
153 cs_log("channel change: sid = %x, vpid = %x. apid = %x", chan
.service_id
, chan
.v_pid
, chan
.a_pid
);
155 openxcas_video_pid
= chan
.v_pid
;
156 openxcas_audio_pid
= chan
.a_pid
;
157 openxcas_data_pid
= chan
.d_pid
;
159 case OPENXCAS_START_PMT_ECM
:
160 cs_log_dbg(D_DVBAPI
, "OPENXCAS_START_PMT_ECM");
164 if(!cs_malloc(&dest
, msg
.buf_len
+ 7 - 12 - 4))
167 memcpy(dest
, "\x03\xFF\xFF\x00\x00\x13\x00", 7);
169 dest
[1] = msg
.buf
[3];
170 dest
[2] = msg
.buf
[4];
171 dest
[5] = msg
.buf
[11] + 1;
173 memcpy(dest
+ 7, msg
.buf
+ 12, msg
.buf_len
- 12 - 4);
175 dvbapi_parse_capmt(dest
, 7 + msg
.buf_len
- 12 - 4, -1, NULL
, 0, 0);
180 memset(&mask
, 0x00, sizeof(mask
));
181 memset(&comp
, 0x00, sizeof(comp
));
186 if((ret
= openxcas_add_filter(msg
.stream_id
, OPENXCAS_FILTER_ECM
, 0, 0xffff, openxcas_ecm_pid
, mask
, comp
, (void *)azbox_openxcas_ecm_callback
)) < 0)
187 { cs_log("unable to add ecm filter"); }
189 { cs_log_dbg(D_DVBAPI
, "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid
, 0); }
191 if(openxcas_start_filter(msg
.stream_id
, msg
.sequence
, OPENXCAS_FILTER_ECM
) < 0)
192 { cs_log("unable to start ecm filter"); }
194 { cs_log_dbg(D_DVBAPI
, "ecm filter started"); }
196 if(!openxcas_create_cipher_ex(msg
.stream_id
, openxcas_seq
, 0, openxcas_ecm_pid
, openxcas_video_pid
, 0xffff, openxcas_audio_pid
, 0xffff, 0xffff, 0xffff))
197 { cs_log("failed to create cipher ex"); }
199 { cs_log_dbg(D_DVBAPI
, "cipher created"); }
201 case OPENXCAS_STOP_PMT_ECM
:
202 cs_log_dbg(D_DVBAPI
, "OPENXCAS_STOP_PMT_ECM");
203 openxcas_stop_filter(msg
.stream_id
, OPENXCAS_FILTER_ECM
);
204 openxcas_remove_filter(msg
.stream_id
, OPENXCAS_FILTER_ECM
);
205 openxcas_stop_filter_ex(msg
.stream_id
, msg
.sequence
, openxcas_filter_idx
);
206 openxcas_destory_cipher_ex(msg
.stream_id
, msg
.sequence
);
207 memset(&demux
, 0, sizeof(demux
));
209 case OPENXCAS_ECM_CALLBACK
:
210 cs_log_dbg(D_DVBAPI
, "OPENXCAS_ECM_CALLBACK");
211 memcpy(&data
, msg
.buf
, msg
.buf_len
);
213 { openxcas_filter_callback(msg
.stream_id
, msg
.sequence
, OPENXCAS_FILTER_ECM
, &data
); }
215 case OPENXCAS_PID_FILTER_CALLBACK
:
216 cs_log_dbg(D_DVBAPI
, "OPENXCAS_PID_FILTER_CALLBACK");
217 memcpy(&data
, msg
.buf
, msg
.buf_len
);
218 openxcas_filter_callback_ex(msg
.stream_id
, msg
.sequence
, &data
);
221 cs_log_dbg(D_DVBAPI
, "OPENXCAS_QUIT");
226 case OPENXCAS_UKNOWN_MSG
:
228 cs_log_dbg(D_DVBAPI
, "OPENXCAS_UKNOWN_MSG (%d)", msg
.cmd
);
229 //cs_log_dump_dbg(D_DVBAPI, &msg, sizeof(msg), "msg dump:");
234 cs_log("invalid message");
238 void azbox_send_dcw(struct s_client
*client
, ECM_REQUEST
*er
)
240 struct s_dvbapi_priority
*delayentry
= dvbapi_check_prio_match(0, demux
[0].pidindex
, 'd');
243 cs_log_dbg(D_DVBAPI
, "send_dcw");
247 if(delayentry
->delay
< 1000)
249 delay
= delayentry
->delay
;
250 cs_log_dbg(D_DVBAPI
, "specific delay: write cw %d ms after ecmrequest", delay
);
253 else if (cfg
.dvbapi_delayer
> 0)
255 delay
= cfg
.dvbapi_delayer
;
256 cs_log_dbg(D_DVBAPI
, "generic delay: write cw %d ms after ecmrequest", delay
);
261 if(cfg
.dvbapi_ecminfo_file
!= 0)
263 dvbapi_write_ecminfo_file(client
, er
, demux
[0].last_cw
[0][0], demux
[0].last_cw
[0][1], 8);
269 for(i
= 0; i
< MAX_DEMUX
; i
++)
271 if(er
->rc
>= E_NOTFOUND
)
273 cs_log_dbg(D_DVBAPI
, "cw not found");
275 if(demux
[i
].pidindex
== -1)
276 { dvbapi_try_next_caid(i
, 0, 0); }
278 openxcas_stop_filter(openxcas_stream_id
, OPENXCAS_FILTER_ECM
);
279 openxcas_remove_filter(openxcas_stream_id
, OPENXCAS_FILTER_ECM
);
283 memset(&mask
, 0x00, sizeof(mask
));
284 memset(&comp
, 0x00, sizeof(comp
));
289 if(openxcas_add_filter(openxcas_stream_id
, OPENXCAS_FILTER_ECM
, 0, 0xffff, openxcas_ecm_pid
, mask
, comp
, (void *)azbox_openxcas_ecm_callback
) < 0)
291 cs_log("unable to add ecm filter (0)");
292 if(openxcas_add_filter(openxcas_stream_id
, OPENXCAS_FILTER_ECM
, openxcas_caid
, 0xffff, openxcas_ecm_pid
, mask
, comp
, (void *)azbox_openxcas_ecm_callback
) < 0)
293 { cs_log("unable to add ecm filter (%04x)", openxcas_caid
); }
295 { cs_log_dbg(D_DVBAPI
, "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid
, openxcas_caid
); }
298 { cs_log_dbg(D_DVBAPI
, "ecm filter added, pid = %x, caid = %x", openxcas_ecm_pid
, 0); }
300 if(openxcas_start_filter(openxcas_stream_id
, openxcas_seq
, OPENXCAS_FILTER_ECM
) < 0)
301 { cs_log("unable to start ecm filter"); }
303 { cs_log_dbg(D_DVBAPI
, "ecm filter started"); }
310 memset(nullcw
, 0, 8);
313 for(n
= 0; n
< 2; n
++)
315 // Skip check for BISS1 - cw could be indeed zero
316 // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
317 if(memcmp(er
->cw
+ (n
* 8), demux
[0].last_cw
[0][n
], 8) && (memcmp(er
->cw
+ (n
* 8), nullcw
, 8) != 0 || caid_is_biss(er
->caid
)))
319 memcpy(demux
[0].last_cw
[0][n
], er
->cw
+ (n
* 8), 8);
320 memcpy(openxcas_cw
+ (n
* 8), er
->cw
+ (n
* 8), 8);
324 if(openxcas_set_key(openxcas_stream_id
, openxcas_seq
, 0, openxcas_cipher_idx
, openxcas_cw
, openxcas_cw
+ 8) != 1)
325 { cs_log("set cw failed"); }
327 { cs_log_dump_dbg(D_DVBAPI
, openxcas_cw
, 16, "write cws to descrambler"); }
330 #ifdef WITH_CARDREADER
331 #define __openxcas_open openxcas_open_with_smartcard
333 #define __openxcas_open openxcas_open
336 void azbox_init(void)
338 openxcas_debug_message_onoff(1); // debug
339 if(__openxcas_open("oscamCAS") < 0)
340 { cs_log("could not init"); }
343 void azbox_close(void)
345 if(openxcas_close() < 0)
346 { cs_log("could not close"); }
349 void *azbox_handler(struct s_client
*cl
, uint8_t *mbuf
, int32_t module_idx
)
351 return dvbapi_start_handler(cl
, mbuf
, module_idx
, azbox_main_thread
);