DVBCore  20.3.0
DVBCore Documentation
stbcikeys.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2016 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2009 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
24 //#define DEBUG_PRINTING_ENABLED
25 
26 /*---includes for this file--------------------------------------------------*/
27 
28 /* compiler library header files */
29 #include <string.h>
30 
31 /* third party header files */
32 
33 /* DVBCore header files */
34 #include "techtype.h"
35 #include "dbgfuncs.h"
36 #include "stbhwos.h"
37 #include "stbci.h"
38 #include "stberc.h"
39 #include "stbdpc.h"
40 #include "stbpvr.h"
41 #include "stbheap.h"
42 #ifdef CI_TA_HANDLES_KEYS
43 #include "stbhwci.h"
44 #endif
45 
46 #include "stbcikeys.h"
47 #include "stbci_int.h"
48 
49 /*---constant definitions for this file--------------------------------------*/
50 
51 #define EVEN_KEY_REGISTER 0
52 #define ODD_KEY_REGISTER 1
53 
54 /*---local typedef enums for this file-------------------------------------*/
55 
56 /*---local typedef structs for this file-------------------------------------*/
57 
58 typedef struct key_info
59 {
60  BOOLEAN valid;
61  BOOLEAN *applied;
62  U8BIT key[16];
63  U8BIT civ[16];
64 } S_KEY_INFO;
65 
66 typedef struct s_cikeys_info
67 {
68  struct s_cikeys_info *next;
69  U8BIT slot_id;
70  U8BIT cipher;
71  BOOLEAN disabled;
72  S_KEY_INFO keys[2];
74 
75 #ifdef CI_TA_HANDLES_KEYS
76 typedef struct s_cikey_avail
77 {
78  BOOLEAN notify;
79  U32BIT obj_ref;
80 } S_CIKEY_AVAIL;
81 #endif
82 
83 /*---local (static) variable declarations for this file----------------------*/
84 /* (internal variables declared static to make them local) */
85 
86 static BOOLEAN *desc_allocated = NULL;
87 static S_CIKEYS_INFO *cikeys_slots = NULL;
88 static void *cikeys_mutex;
89 #ifdef CI_TA_HANDLES_KEYS
90 static S_CIKEY_AVAIL *cikeys_avail = NULL;
91 #endif
92 
93 static S_CIKEYS_INFO *FindSlot(U8BIT slot_id);
94 static void AllocateDescramblers(U8BIT path, U8BIT cipher);
95 static BOOLEAN SetDescramblerKey(U8BIT path, E_STB_DMX_DESC_KEY_PARITY parity,
96  U8BIT cipher, S_KEY_INFO *key_info);
97 
98 
99 /*---global function definitions---------------------------------------------*/
100 
105 {
106  cikeys_mutex = STB_OSCreateMutex();
107 }
108 
113 void STB_CiKeysDisable(U8BIT slot_id)
114 {
115  S_CIKEYS_INFO *slot_info;
116 
117  FUNCTION_START(STB_CiKeysDisable);
118 
119  DBGPRINT("(slot=%u)", slot_id)
120 
121  slot_info = FindSlot(slot_id);
122  if (slot_info != NULL)
123  {
124  slot_info->disabled = TRUE;
125  }
126  FUNCTION_FINISH(STB_CiKeysDisable);
127 }
128 
133 void STB_CiKeysRemove(U8BIT slot_id)
134 {
135  S_CIKEYS_INFO *slot;
136  S_CIKEYS_INFO **pslot;
137 
138  FUNCTION_START(STB_CiKeysRemove);
139  DBGPRINT("(slot=%u)", slot_id)
140  pslot = &cikeys_slots;
141  STB_OSMutexLock(cikeys_mutex);
142  slot = cikeys_slots;
143  while (slot != NULL)
144  {
145  if (slot->slot_id == slot_id)
146  {
147  *pslot = slot->next;
148  STB_FreeMemory(slot);
149  break;
150  }
151  pslot = &(slot->next);
152  slot = slot->next;
153  }
154  STB_OSMutexUnlock(cikeys_mutex);
155 
156  FUNCTION_FINISH(STB_CiKeysRemove);
157 }
158 
167 void STB_CINotifyCCKey(U8BIT slot_id, U8BIT cipher, U8BIT key_register,
168  U8BIT *key, U8BIT *civ)
169 {
170  S_CIKEYS_INFO *slot_info;
171  U8BIT path, num_paths;
172 
173  FUNCTION_START(STB_CINotifyCCKey);
174 
175  DBGPRINT("slot_id = %u, cipher = %s, key_register = %u",
176  slot_id,
177  cipher == STB_CI_CIPHER_DES ? "STB_CI_CIPHER_DES" :
178  cipher == STB_CI_CIPHER_AES ? "STB_CI_CIPHER_AES" :
179  "UNKNOWN",
180  key_register)
181 
182  slot_info = FindSlot(slot_id);
183  num_paths = STB_DPGetNumPaths();
184  if (slot_info == NULL)
185  {
186  slot_info = STB_GetMemory(sizeof(S_CIKEYS_INFO)+ (2 * num_paths * sizeof(BOOLEAN)));
187  if (slot_info != NULL)
188  {
189  slot_info->disabled = FALSE;
190  slot_info->keys[EVEN_KEY_REGISTER].applied = (BOOLEAN*)(slot_info + 1);
191  memset(slot_info->keys[EVEN_KEY_REGISTER].applied, 0, 2 * num_paths * sizeof(BOOLEAN));
192  slot_info->keys[ODD_KEY_REGISTER].applied = slot_info->keys[EVEN_KEY_REGISTER].applied + num_paths;
193  slot_info->keys[EVEN_KEY_REGISTER].valid = FALSE;
194  slot_info->keys[ODD_KEY_REGISTER].valid = FALSE;
195  slot_info->slot_id = slot_id;
196  DBGPRINT("Add slot info; id=%u", slot_id)
197 
198  STB_OSMutexLock(cikeys_mutex);
199  slot_info->next = cikeys_slots;
200  cikeys_slots = slot_info;
201  STB_OSMutexUnlock(cikeys_mutex);
202 
203  if (desc_allocated == NULL)
204  {
205  desc_allocated = STB_GetMemory(num_paths * sizeof(BOOLEAN));
206  if (desc_allocated != NULL)
207  {
208  for (path = 0; path != num_paths; path++)
209  {
210  desc_allocated[path] = FALSE;
211  }
212  }
213  }
214  }
215  }
216  if (slot_info != NULL)
217  {
218  /* Store CC keys */
219  if ((key_register == EVEN_KEY_REGISTER) ||
220  (key_register == ODD_KEY_REGISTER))
221  {
222  slot_info->cipher = cipher;
223  if (cipher == STB_CI_CIPHER_AES)
224  {
225  memcpy(slot_info->keys[key_register].key, key, 16);
226  memcpy(slot_info->keys[key_register].civ, civ, 16);
227  }
228  else
229  {
230  memcpy(slot_info->keys[key_register].key, key, 8);
231  }
232  slot_info->keys[key_register].valid = TRUE;
233 
234  for (path = 0; path != num_paths; path++)
235  {
236  slot_info->keys[key_register].applied[path] = FALSE;
237  }
238 
239  DBGPRINT("Send CI KEYS changed/updated slot=%u", slot_id)
240  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_KEYS_UPDATED, &slot_id, sizeof(U8BIT));
241  }
242  }
243 
244  FUNCTION_FINISH(STB_CINotifyCCKey);
245 }
246 
247 #ifdef CI_TA_HANDLES_KEYS
248 
258 void STB_CINotifyCckAvailable(U8BIT slot_id, U32BIT obj_ref)
259 {
260  U8BIT num_slots;
261  FUNCTION_START(STB_CINotifyCckAvailable);
262  DBGPRINT("slot=%u oref=%x", slot_id, obj_ref)
263  num_slots = STB_CIGetSlotCount();
264  if (slot_id > num_slots)
265  {
266  DBGPRINT("Error: bad slot_id %u", slot_id)
267  }
268  else
269  {
270  if (cikeys_avail == NULL)
271  {
272  cikeys_avail = (S_CIKEY_AVAIL *)STB_GetMemory(num_slots * sizeof(S_CIKEY_AVAIL));
273  if (cikeys_avail != NULL)
274  {
275  memset(cikeys_avail, 0, num_slots * sizeof(S_CIKEY_AVAIL));
276  }
277  }
278  if (cikeys_avail != NULL)
279  {
280  cikeys_avail[slot_id].obj_ref = obj_ref;
281  cikeys_avail[slot_id].notify = TRUE;
282 
283  DBGPRINT("Send CI KEYS changed/updated slot=%u", slot_id)
284  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_KEYS_UPDATED, &slot_id, sizeof(U8BIT));
285  }
286  }
287  FUNCTION_FINISH(STB_CINotifyCckAvailable);
288 }
289 
290 #endif /*CI_TA_HANDLES_KEYS*/
291 
297 void STB_CiKeysApply(U8BIT path, U8BIT slot_id)
298 {
299  S_CIKEYS_INFO *slot_info;
300 
301  FUNCTION_START(STB_CiKeysApply);
302 
303  DBGPRINT("(path=%u,slot=%u)", path, slot_id)
304 
305  slot_info = FindSlot(slot_id);
306  if (slot_info != NULL)
307  {
308  if (((slot_info->keys[EVEN_KEY_REGISTER].valid) &&
309  (!slot_info->keys[EVEN_KEY_REGISTER].applied[path])) ||
310  ((slot_info->keys[ODD_KEY_REGISTER].valid) &&
311  (!slot_info->keys[ODD_KEY_REGISTER].applied[path])))
312  {
313  if (STB_DPIsDecodingPath(path))
314  {
315  if ((desc_allocated != NULL) && (!desc_allocated[path]))
316  {
317  /* Allocate descramblers (if required) */
318  DBGPRINT("Allocating descramblers")
319  AllocateDescramblers(path, slot_info->cipher);
320  }
321 
322  if ((desc_allocated != NULL) && (desc_allocated[path]))
323  {
324  if ((slot_info->keys[EVEN_KEY_REGISTER].valid) &&
325  (!slot_info->keys[EVEN_KEY_REGISTER].applied[path]))
326  {
327  DBGPRINT("Setting descrambler even keys")
328  if (SetDescramblerKey(path, KEY_PARITY_EVEN, slot_info->cipher,
329  &slot_info->keys[EVEN_KEY_REGISTER]))
330  {
331  slot_info->keys[EVEN_KEY_REGISTER].applied[path] = TRUE;
332  }
333  }
334  if ((slot_info->keys[ODD_KEY_REGISTER].valid) &&
335  (!slot_info->keys[ODD_KEY_REGISTER].applied[path]))
336  {
337  DBGPRINT("Setting descrambler odd keys")
338  if (SetDescramblerKey(path, KEY_PARITY_ODD, slot_info->cipher,
339  &slot_info->keys[ODD_KEY_REGISTER]))
340  {
341  slot_info->keys[ODD_KEY_REGISTER].applied[path] = TRUE;
342  }
343  }
344  }
345  }
346 
347  if (STB_DPIsRecordingPath(path))
348  {
349  /* Need to let the PVR code know the keys so they can be used when recording */
350  if ((slot_info->keys[EVEN_KEY_REGISTER].valid) &&
351  (!slot_info->keys[EVEN_KEY_REGISTER].applied[path]))
352  {
353  DBGPRINT("(%u) Saving descrambler even keys", path)
354 
355  STB_PVRSetDescramblerKey(path, slot_info->cipher, KEY_PARITY_EVEN,
356  slot_info->keys[EVEN_KEY_REGISTER].key, slot_info->keys[EVEN_KEY_REGISTER].civ);
357  slot_info->keys[EVEN_KEY_REGISTER].applied[path] = TRUE;
358  }
359 
360  if ((slot_info->keys[ODD_KEY_REGISTER].valid) &&
361  (!slot_info->keys[ODD_KEY_REGISTER].applied[path]))
362  {
363  DBGPRINT("(%u): Saving descrambler odd keys", path)
364 
365  STB_PVRSetDescramblerKey(path, slot_info->cipher, KEY_PARITY_ODD,
366  slot_info->keys[ODD_KEY_REGISTER].key, slot_info->keys[ODD_KEY_REGISTER].civ);
367  slot_info->keys[ODD_KEY_REGISTER].applied[path] = TRUE;
368  }
369  }
370  }
371  }
372 #ifdef CI_TA_HANDLES_KEYS
373  else if (cikeys_avail != NULL && cikeys_avail[slot_id].notify)
374  {
375  if (STB_DPIsDecodingPath(path) || STB_DPIsRecordingPath(path))
376  {
377  /* Tell CI+ Trusted App to inform demux of Content Control keys */
378  STB_CISendCckToDemuxTa(slot_id, cikeys_avail[slot_id].obj_ref, path);
379  }
380  cikeys_avail[slot_id].notify = FALSE;
381  }
382 #endif
383 
384  FUNCTION_FINISH(STB_CiKeysApply);
385 }
386 
392 void STB_CiKeysClear(U8BIT path, U8BIT slot_id)
393 {
394  U8BIT demux;
395  S_CIKEYS_INFO *slot_info;
396 
397  FUNCTION_START(STB_CiKeysClear);
398 
399  DBGPRINT("(path=%u)", path)
400 
401  demux = STB_DPGetPathDemux(path);
402  DBGPRINT("(%u): demux=%u", path, demux)
403  if (demux != INVALID_RES_ID)
404  {
405  if ((desc_allocated != NULL) && (desc_allocated[path]))
406  {
407  DBGPRINT("Freeing descramblers")
408  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_AUDIO);
409  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_VIDEO);
410  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_TEXT);
411  desc_allocated[path] = FALSE;
412  }
413 
414  slot_info = FindSlot(slot_id);
415  if (slot_info != NULL)
416  {
417  slot_info->keys[EVEN_KEY_REGISTER].applied[path] = FALSE;
418  slot_info->keys[ODD_KEY_REGISTER].applied[path] = FALSE;
419  }
420  }
421 
422  FUNCTION_FINISH(STB_CiKeysClear);
423 }
424 
425 /*---local function definitions----------------------------------------------*/
426 
427 static S_CIKEYS_INFO *FindSlot(U8BIT slot_id)
428 {
429  S_CIKEYS_INFO *slot_info;
430  STB_OSMutexLock(cikeys_mutex);
431  slot_info = cikeys_slots;
432  while (slot_info != NULL)
433  {
434  if (slot_info->slot_id == slot_id)
435  {
436  if (slot_info->disabled)
437  {
438  slot_info = NULL;
439  }
440  break;
441  }
442  slot_info = slot_info->next;
443  }
444  STB_OSMutexUnlock(cikeys_mutex);
445  return slot_info;
446 }
447 
454 static void AllocateDescramblers(U8BIT path, U8BIT cipher)
455 {
456  BOOLEAN result;
457  E_STB_DMX_DESC_TYPE type;
458  U8BIT demux;
459 
460  FUNCTION_START(AllocateDescramblers);
461 
462  demux = STB_DPGetPathDemux(path);
463  if (desc_allocated != NULL && demux != INVALID_RES_ID)
464  {
465  switch (cipher)
466  {
467  case STB_CI_CIPHER_DES:
468  type = DESC_TYPE_DES;
469  break;
470  case STB_CI_CIPHER_AES:
471  type = DESC_TYPE_AES;
472  break;
473  }
474 
475  result = STB_DMXGetDescramblerKey(demux, DESC_TRACK_AUDIO);
476  if (result)
477  {
478  STB_DMXSetKeyUsage(demux, DESC_TRACK_AUDIO, KEY_USAGE_TRANSPORT);
479  STB_DMXSetDescramblerType(demux, DESC_TRACK_AUDIO, type);
480 
481  result = STB_DMXGetDescramblerKey(demux, DESC_TRACK_VIDEO);
482  if (result)
483  {
484  STB_DMXSetKeyUsage(demux, DESC_TRACK_VIDEO, KEY_USAGE_TRANSPORT);
485  STB_DMXSetDescramblerType(demux, DESC_TRACK_VIDEO, type);
486 
487  result = STB_DMXGetDescramblerKey(demux, DESC_TRACK_TEXT);
488  if (result)
489  {
490  STB_DMXSetKeyUsage(demux, DESC_TRACK_TEXT, KEY_USAGE_TRANSPORT);
491  STB_DMXSetDescramblerType(demux, DESC_TRACK_TEXT, type);
492 
493  DBGPRINT("Descramblers allocated successfully")
494  desc_allocated[path] = TRUE;
495  }
496  else
497  {
498  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_VIDEO);
499  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_AUDIO);
500  }
501  }
502  else
503  {
504  STB_DMXFreeDescramblerKey(demux, DESC_TRACK_AUDIO);
505  }
506  }
507 
508  if (!desc_allocated[path])
509  {
510  DBGPRINT("Could not allocate descramblers")
511  }
512  }
513 
514  FUNCTION_FINISH(AllocateDescramblers);
515 }
516 
523 static BOOLEAN SetDescramblerKey(U8BIT path, E_STB_DMX_DESC_KEY_PARITY parity,
524  U8BIT cipher, S_KEY_INFO *key_info)
525 {
526  U8BIT *key_data;
527  U8BIT key_buffer[32];
528  BOOLEAN result;
529  U8BIT demux;
530 
531  FUNCTION_START(SetDescramblerKey);
532 
533  result = FALSE;
534 
535  demux = STB_DPGetPathDemux(path);
536  if (key_info->valid && demux != INVALID_RES_ID)
537  {
538  switch (cipher)
539  {
540  case STB_CI_CIPHER_DES:
541  key_data = key_info->key;
542  break;
543  case STB_CI_CIPHER_AES:
544  memcpy(key_buffer, key_info->key, 16);
545  memcpy(key_buffer + 16, key_info->civ, 16);
546  key_data = key_buffer;
547  break;
548  }
549 
550  result = STB_DMXSetDescramblerKeyData(demux, DESC_TRACK_AUDIO, parity, key_data);
551  DBGPRINT("STB_DMXSetDescramblerKeyData(%d, DESC_TRACK_AUDIO) returned %d", demux, result)
552  result = STB_DMXSetDescramblerKeyData(demux, DESC_TRACK_VIDEO, parity, key_data);
553  DBGPRINT("STB_DMXSetDescramblerKeyData(%d, DESC_TRACK_VIDEO) returned %d", demux, result)
554  result = STB_DMXSetDescramblerKeyData(demux, DESC_TRACK_TEXT, parity, key_data);
555  DBGPRINT("STB_DMXSetDescramblerKeyData(%d, DESC_TRACK_TEXT) returned %d", demux, result)
556  }
557 
558  FUNCTION_FINISH(SetDescramblerKey);
559  return(result);
560 }
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
BOOLEAN STB_DMXGetDescramblerKey(U8BIT path, E_STB_DMX_DESC_TRACK track)
Acquires a descrambler for the specified track on this path.
void STB_CiKeysApply(U8BIT path, U8BIT slot_id)
Apply stored CC keys (if any) on given path.
Definition: stbcikeys.c:297
Header file - macros and function prototypes for public use.
void STB_OSMutexUnlock(void *mutex)
Unlock a mutex (a.k.a. &#39;leave&#39;, &#39;signal&#39; or &#39;release&#39;)
void STB_CiKeysRemove(U8BIT slot_id)
Notify module removal.
Definition: stbcikeys.c:133
Header file - macros and function prototypes for public use.
void STB_ERSendEvent(BOOLEAN latched, BOOLEAN repeat, U16BIT path_class, U16BIT type, void *data, U32BIT data_size)
Sends an event to event reporting control module.
Definition: stberc.c:571
BOOLEAN STB_DMXSetDescramblerKeyData(U8BIT path, E_STB_DMX_DESC_TRACK track, E_STB_DMX_DESC_KEY_PARITY parity, U8BIT *data)
Set the descrambler key data for the specified track on this path.
U8BIT STB_DPGetNumPaths(void)
Returns the maximum number of decode paths.
Definition: stbdpc.c:532
void STB_CiKeysDisable(U8BIT slot_id)
Disable CC keys for slot, as CAM has been removed.
Definition: stbcikeys.c:113
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
BOOLEAN STB_DPIsDecodingPath(U8BIT path)
Is the given decode path being used for decoding.
Definition: stbdpc.c:1346
BOOLEAN STB_DMXSetDescramblerType(U8BIT path, E_STB_DMX_DESC_TRACK track, E_STB_DMX_DESC_TYPE type)
Set the descrambler type for the specified track on this path.
Debug functions header file.
void STB_OSMutexLock(void *mutex)
Lock a mutex (a.k.a. &#39;enter&#39;, &#39;wait&#39; or &#39;get&#39;).
CI Content Control - descrambler keys.
Header file - Function prototypes for Event Reporting.
CI Content Control support - internal header.
BOOLEAN STB_DMXSetKeyUsage(U8BIT path, E_STB_DMX_DESC_TRACK track, E_STB_DMX_KEY_USAGE key_usage)
Set the descrambler key usage for the specified track on this path.
void STB_CINotifyCCKey(U8BIT slot_id, U8BIT cipher, U8BIT key_register, U8BIT *key, U8BIT *civ)
Handle content control keys.
Definition: stbcikeys.c:167
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
BOOLEAN STB_DPIsRecordingPath(U8BIT path)
Is the given decode path being used for recording.
Definition: stbdpc.c:1320
void STB_CiKeysInitialise(void)
CI descrambler keys support initialise.
Definition: stbcikeys.c:104
Header file - Function prototypes for heap memory.
void * STB_OSCreateMutex(void)
Create a mutex.
void STB_CiKeysClear(U8BIT path, U8BIT slot_id)
Clear CC keys (if any) from given path.
Definition: stbcikeys.c:392
#define DBGPRINT(...)
Definition: dbgfuncs.h:74
BOOLEAN STB_DMXFreeDescramblerKey(U8BIT path, E_STB_DMX_DESC_TRACK track)
Frees the descrambler for the specified track on this path.
U8BIT STB_DPGetPathDemux(U8BIT path)
Returns the demux path ID acquired by the given decode path.
Definition: stbdpc.c:1711