| /* |
| * 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; |
| } |