blob: a1fe1de412c38ce434ef9cd9d24becdf6a1e9288 [file] [log] [blame]
/*
* camconditionalaccess.c - CAM (EN50221) Conditional Access resource
* Copyright (C) 2007 Alessandro Decina
*
* Authors:
* Alessandro Decina <alessandro@nnva.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <string.h>
#include "camutils.h"
#include "camconditionalaccess.h"
#define GST_CAT_DEFAULT cam_debug_cat
#define TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY 0x9F8030
#define TAG_CONDITIONAL_ACCESS_INFO_REPLY 0x9F8031
#define TAG_CONDITIONAL_ACCESS_PMT 0x9F8032
#define TAG_CONDITIONAL_ACCESS_PMT_REPLY 0x9F8033
static CamReturn session_request_impl (CamALApplication * application,
CamSLSession * session, CamSLResourceStatus * status);
static CamReturn open_impl (CamALApplication * application,
CamSLSession * session);
static CamReturn close_impl (CamALApplication * application,
CamSLSession * session);
static CamReturn data_impl (CamALApplication * application,
CamSLSession * session, guint tag, guint8 * buffer, guint length);
CamConditionalAccess *
cam_conditional_access_new (void)
{
CamConditionalAccess *cas;
CamALApplication *application;
cas = g_new0 (CamConditionalAccess, 1);
application = CAM_AL_APPLICATION (cas);
_cam_al_application_init (application);
application->resource_id = CAM_AL_CONDITIONAL_ACCESS_ID;
application->session_request = session_request_impl;
application->open = open_impl;
application->close = close_impl;
application->data = data_impl;
cas->ready = FALSE;
return cas;
}
void
cam_conditional_access_destroy (CamConditionalAccess * cas)
{
_cam_al_application_destroy (CAM_AL_APPLICATION (cas));
g_free (cas);
}
static CamReturn
send_ca_pmt (CamConditionalAccess * cas, GstMpegtsPMT * pmt,
guint8 list_management, guint8 cmd_id)
{
CamReturn ret;
guint8 *buffer;
guint buffer_size;
guint offset;
guint8 *ca_pmt;
guint ca_pmt_size;
GList *walk;
ca_pmt = cam_build_ca_pmt (pmt, list_management, cmd_id, &ca_pmt_size);
cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al,
ca_pmt_size, &buffer_size, &offset);
buffer = g_malloc0 (buffer_size);
memcpy (buffer + offset, ca_pmt, ca_pmt_size);
for (walk = CAM_AL_APPLICATION (cas)->sessions; walk; walk = walk->next) {
CamSLSession *session = CAM_SL_SESSION (walk->data);
ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
TAG_CONDITIONAL_ACCESS_PMT, buffer, buffer_size, ca_pmt_size);
if (CAM_FAILED (ret)) {
GST_ERROR ("error sending ca_pmt to slot %d, error: %d",
session->connection->slot, ret);
continue;
}
}
g_free (ca_pmt);
g_free (buffer);
return CAM_RETURN_OK;
}
CamReturn
cam_conditional_access_set_pmt (CamConditionalAccess * cas,
GstMpegtsPMT * pmt, CamConditionalAccessPmtFlag flag)
{
return send_ca_pmt (cas, pmt, flag, 0x01 /* ok_descrambling */ );
}
static CamReturn
send_simple (CamConditionalAccess * cas, CamSLSession * session, guint tag)
{
guint8 *buffer;
guint offset;
guint buffer_size;
CamReturn ret;
cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al, 0, &buffer_size,
&offset);
buffer = g_malloc (buffer_size);
ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
tag, buffer, buffer_size, 0);
g_free (buffer);
return ret;
}
static CamReturn
send_conditional_access_enquiry (CamConditionalAccess * cas,
CamSLSession * session)
{
GST_DEBUG ("sending application CAS enquiry");
return send_simple (cas, session, TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY);
}
static CamReturn
session_request_impl (CamALApplication * application,
CamSLSession * session, CamSLResourceStatus * status)
{
*status = CAM_SL_RESOURCE_STATUS_OPEN;
return CAM_RETURN_OK;
}
static CamReturn
open_impl (CamALApplication * application, CamSLSession * session)
{
CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
GST_INFO ("opening conditional access session %d", session->session_nb);
return send_conditional_access_enquiry (cas, session);
}
static CamReturn
close_impl (CamALApplication * application, CamSLSession * session)
{
GST_INFO ("closing conditional access session %d", session->session_nb);
return CAM_RETURN_OK;
}
static CamReturn
handle_conditional_access_info_reply (CamConditionalAccess * cas,
CamSLSession * session, guint8 * buffer, guint length)
{
#ifndef GST_DISABLE_GST_DEBUG
int i;
guint16 cas_id;
GST_INFO ("conditional access info enquiry reply");
for (i = 0; i < length / 2; ++i) {
cas_id = GST_READ_UINT16_BE (buffer);
GST_INFO ("slot %d, cas_id 0x%x", session->connection->slot, cas_id);
buffer += 2;
}
cas->ready = TRUE;
#endif
return CAM_RETURN_OK;
}
static CamReturn
handle_conditional_access_pmt_reply (CamConditionalAccess * cas,
CamSLSession * session, guint8 * buffer, guint length)
{
#ifndef GST_DISABLE_GST_DEBUG
guint16 program_num;
guint8 version_num, current_next_indicator;
GST_INFO ("conditional access PMT reply");
program_num = GST_READ_UINT16_BE (buffer);
buffer += 2;
GST_INFO ("program_number : %d", program_num);
version_num = *buffer >> 1 & 0x1f;
current_next_indicator = *buffer & 0x1;
buffer++;
GST_INFO ("version_num:%d, current_next_indicator:%d",
version_num, current_next_indicator);
GST_INFO ("CA_enable : %d (0x%x)", *buffer >> 7 ? *buffer & 0x7f : 0,
*buffer);
buffer++;
length -= 4;
while (length > 0) {
guint16 PID = GST_READ_UINT16_BE (buffer);
buffer += 2;
GST_INFO ("PID 0x%x CA_enable : %d (0x%x)", PID,
*buffer >> 7 ? *buffer & 0x7f : 0, *buffer);
buffer++;
length -= 3;
}
#endif
return CAM_RETURN_OK;
}
static CamReturn
data_impl (CamALApplication * application, CamSLSession * session,
guint tag, guint8 * buffer, guint length)
{
CamReturn ret;
CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
switch (tag) {
case TAG_CONDITIONAL_ACCESS_INFO_REPLY:
ret = handle_conditional_access_info_reply (cas, session, buffer, length);
break;
case TAG_CONDITIONAL_ACCESS_PMT_REPLY:
ret = handle_conditional_access_pmt_reply (cas, session, buffer, length);
break;
default:
GST_WARNING ("Got unknown callback, tag 0x%x", tag);
g_return_val_if_reached (CAM_RETURN_ERROR);
}
return ret;
}