summaryrefslogtreecommitdiffstats
path: root/sys/dvb/camsession.c
diff options
context:
space:
mode:
authorAlessandro Decina <alessandro@nnva.org>2007-10-16 17:38:05 +0000
committerZaheer Abbas Merali <zaheerabbas@merali.org>2007-10-16 17:38:05 +0000
commitc205b740d4e793354493c4a2663e45670255453c (patch)
tree3c5d8978e68cf860b69c279e14372ccc144a883c /sys/dvb/camsession.c
parent389904f6248c65468175c072441747f51c5a5296 (diff)
downloadgst-plugins-bad-c205b740d4e793354493c4a2663e45670255453c.tar.gz
gst-plugins-bad-c205b740d4e793354493c4a2663e45670255453c.tar.bz2
gst-plugins-bad-c205b740d4e793354493c4a2663e45670255453c.zip
sys/dvb/: Integrate SoC work done by Alessandro for the Freevo project.
Original commit message from CVS: patch by: Alessandro Decina * sys/dvb/Makefile.am: * sys/dvb/cam.c: * sys/dvb/cam.h: * sys/dvb/camapplication.c: * sys/dvb/camapplication.h: * sys/dvb/camapplicationinfo.c: * sys/dvb/camapplicationinfo.h: * sys/dvb/camconditionalaccess.c: * sys/dvb/camconditionalaccess.h: * sys/dvb/camdevice.c: * sys/dvb/camdevice.h: * sys/dvb/camresourcemanager.c: * sys/dvb/camresourcemanager.h: * sys/dvb/camsession.c: * sys/dvb/camsession.h: * sys/dvb/camswclient.c: * sys/dvb/camswclient.h: * sys/dvb/camtransport.c: * sys/dvb/camtransport.h: * sys/dvb/camutils.c: * sys/dvb/camutils.h: * sys/dvb/dvbbasebin.c: * sys/dvb/dvbbasebin.h: * sys/dvb/gstdvb.c: * sys/dvb/gstdvbsrc.c: * sys/dvb/gstdvbsrc.h: Integrate SoC work done by Alessandro for the Freevo project. Adds cam support to the dvb stack in GStreamer and a new element (actually a bin) called dvbbasebin that integrates dvbsrc and mpegtsparse to a) handle decryption and b) allow acquiring multiple channels on same transponder without knowing pid numbers.
Diffstat (limited to 'sys/dvb/camsession.c')
-rw-r--r--sys/dvb/camsession.c595
1 files changed, 595 insertions, 0 deletions
diff --git a/sys/dvb/camsession.c b/sys/dvb/camsession.c
new file mode 100644
index 00000000..6a2deb9c
--- /dev/null
+++ b/sys/dvb/camsession.c
@@ -0,0 +1,595 @@
+/*
+ * camsession.c - GStreamer CAM (EN50221) Session Layer
+ * Copyright (C) 2007 Alessandro Decina
+ *
+ * Authors:
+ * Alessandro Decina <alessandro@nnva.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "camsession.h"
+
+#define GST_CAT_DEFAULT cam_debug_cat
+#define I_TAG 0
+#define I_LENGTH_FB 1
+
+#define TAG_SESSION_NUMBER 0x90
+#define TAG_OPEN_SESSION_REQUEST 0x91
+#define TAG_OPEN_SESSION_RESPONSE 0x92
+#define TAG_CREATE_SESSION 0x93
+#define TAG_CREATE_SESSION_RESPONSE 0x94
+#define TAG_CLOSE_SESSION_REQUEST 0x95
+#define TAG_CLOSE_SESSION_RESPONSE 0x96
+
+static CamReturn connection_data_cb (CamTL * tl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length);
+
+CamSLSession *
+cam_sl_session_new (CamSL * sl, CamTLConnection * connection,
+ guint16 session_nb, guint resource_id)
+{
+ CamSLSession *session = g_new0 (CamSLSession, 1);
+
+ session->state = CAM_SL_SESSION_STATE_IDLE;
+ session->sl = sl;
+ session->connection = connection;
+ session->session_nb = session_nb;
+ session->resource_id = resource_id;
+
+ return session;
+}
+
+void
+cam_sl_session_destroy (CamSLSession * session)
+{
+ g_free (session);
+}
+
+CamSL *
+cam_sl_new (CamTL * tl)
+{
+ CamSL *sl = g_new0 (CamSL, 1);
+
+ sl->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ NULL, (GDestroyNotify) cam_sl_session_destroy);
+
+ tl->user_data = sl;
+ tl->connection_data = connection_data_cb;
+
+ return sl;
+}
+
+void
+cam_sl_destroy (CamSL * sl)
+{
+ g_hash_table_destroy (sl->sessions);
+
+ g_free (sl);
+}
+
+CamReturn
+cam_sl_create_session (CamSL * sl,
+ CamTLConnection * connection, guint resource_id,
+ CamSLSession ** out_session)
+{
+ CamReturn ret;
+ CamSLSession *session = NULL;
+ guint size;
+ guint offset;
+ guint8 *tpdu = NULL;
+ guint8 *spdu;
+ guint16 session_nb;
+
+ /* FIXME: implement session number allocations properly */
+ if (sl->session_ids == G_MAXUINT16)
+ return CAM_RETURN_SESSION_TOO_MANY_SESSIONS;
+
+ session_nb = ++sl->session_ids;
+ session = cam_sl_session_new (sl, connection, session_nb, resource_id);
+
+ /* SPDU layout (8 bytes):
+ * TAG_CREATE_SESSION 1 byte
+ * length_field () 1 byte
+ * resource_id 4 bytes
+ * session_nb 2 bytes
+ */
+
+ /* get TPDU size */
+ cam_tl_calc_buffer_size (sl->tl, 8, &size, &offset);
+
+ tpdu = (guint8 *) g_malloc (size);
+ spdu = tpdu + offset;
+
+ /* SPDU header */
+ /* tag */
+ spdu[0] = TAG_CREATE_SESSION;
+ /* fixed length_field */
+ spdu[1] = 6;
+
+ /* SPDU body */
+ /* resource id */
+ GST_WRITE_UINT32_BE (&spdu[2], resource_id);
+ /* session_nb */
+ GST_WRITE_UINT16_BE (&spdu[6], session_nb);
+
+ /* write the TPDU */
+ ret = cam_tl_connection_write (session->connection, tpdu, size, 8);
+ if (CAM_FAILED (ret))
+ goto error;
+
+ *out_session = session;
+
+ g_free (tpdu);
+ return CAM_RETURN_OK;
+
+error:
+ if (session)
+ cam_sl_session_destroy (session);
+
+ g_free (tpdu);
+
+ return ret;
+}
+
+/* send a TAG_CLOSE_SESSION SPDU */
+CamReturn
+cam_sl_session_close (CamSLSession * session)
+{
+ CamReturn ret;
+ guint size;
+ guint offset;
+ guint8 *tpdu = NULL;
+ guint8 *spdu;
+ CamSL *sl = session->sl;
+
+ /* SPDU layout (4 bytes):
+ * TAG_CLOSE_SESSION 1 byte
+ * length_field () 1 byte
+ * session_nb 2 bytes
+ */
+
+ /* get the size of the TPDU */
+ cam_tl_calc_buffer_size (sl->tl, 4, &size, &offset);
+
+ tpdu = (guint8 *) g_malloc (size);
+ /* the spdu header starts after the TPDU headers */
+ spdu = tpdu + offset;
+
+ /* SPDU header */
+ /* tag */
+ spdu[0] = TAG_CLOSE_SESSION_REQUEST;
+ /* fixed length_field */
+ spdu[1] = 2;
+ /* SPDU body */
+ /* session_nb */
+ GST_WRITE_UINT16_BE (&spdu[2], session->session_nb);
+
+ /* write the TPDU */
+ ret = cam_tl_connection_write (session->connection, tpdu, size, 4);
+ if (CAM_FAILED (ret))
+ goto error;
+
+ session->state = CAM_SL_SESSION_STATE_CLOSING;
+
+ g_free (tpdu);
+
+ return CAM_RETURN_OK;
+
+error:
+ g_free (tpdu);
+
+ return ret;
+}
+
+void
+cam_sl_calc_buffer_size (CamSL * sl, guint body_length,
+ guint * buffer_size, guint * offset)
+{
+ /* an APDU is sent in a SESSION_NUMBER SPDU, which has a fixed header size (4
+ * bytes) */
+ cam_tl_calc_buffer_size (sl->tl, 4 + body_length, buffer_size, offset);
+ *offset += 4;
+}
+
+CamReturn
+cam_sl_session_write (CamSLSession * session,
+ guint8 * buffer, guint buffer_size, guint body_length)
+{
+ guint8 *spdu;
+
+ /* SPDU layout (4 + body_length bytes):
+ * TAG_SESSION_NUMBER (1 byte)
+ * length_field (1 byte)
+ * session number (2 bytes)
+ * one or more APDUs (body_length bytes)
+ */
+
+ spdu = (buffer + buffer_size) - body_length - 4;
+ spdu[0] = TAG_SESSION_NUMBER;
+ spdu[1] = 2;
+ GST_WRITE_UINT16_BE (&spdu[2], session->session_nb);
+
+ /* add our header to the body length */
+ return cam_tl_connection_write (session->connection,
+ buffer, buffer_size, 4 + body_length);
+}
+
+static CamReturn
+send_open_session_response (CamSL * sl, CamSLSession * session, guint8 status)
+{
+ CamReturn ret;
+ guint8 *tpdu;
+ guint size;
+ guint offset;
+ guint8 *spdu;
+
+ /* SPDU layout (9 bytes):
+ * TAG_OPEN_SESSION_RESPONSE 1 byte
+ * length_field () 1 byte
+ * session_status 1 byte
+ * resource_id 4 bytes
+ * session_nb 2 bytes
+ */
+
+ cam_tl_calc_buffer_size (session->sl->tl, 9, &size, &offset);
+
+ tpdu = g_malloc0 (size);
+ spdu = tpdu + offset;
+
+ spdu[0] = TAG_OPEN_SESSION_RESPONSE;
+ /* fixed length_field () */
+ spdu[1] = 7;
+ spdu[2] = status;
+ GST_WRITE_UINT32_BE (&spdu[3], session->resource_id);
+ GST_WRITE_UINT16_BE (&spdu[7], session->session_nb);
+
+ ret = cam_tl_connection_write (session->connection, tpdu, size, 9);
+ g_free (tpdu);
+ if (CAM_FAILED (ret))
+ return ret;
+
+ return CAM_RETURN_OK;
+}
+
+static CamReturn
+send_close_session_response (CamSL * sl, CamSLSession * session, guint8 status)
+{
+ CamReturn ret;
+ guint8 *tpdu;
+ guint size;
+ guint offset;
+ guint8 *spdu;
+
+ /* SPDU layout (5 bytes):
+ * TAG_CLOSE_SESSION_RESPONSE 1 byte
+ * length_field () 1 byte
+ * session_status 1 byte
+ * session_nb 2 bytes
+ */
+
+ cam_tl_calc_buffer_size (session->sl->tl, 5, &size, &offset);
+
+ tpdu = g_malloc0 (size);
+ spdu = tpdu + offset;
+
+ spdu[0] = TAG_OPEN_SESSION_RESPONSE;
+ /* fixed length_field() */
+ spdu[1] = 3;
+ spdu[2] = status;
+ GST_WRITE_UINT16_BE (&spdu[3], session->session_nb);
+
+ ret = cam_tl_connection_write (session->connection, tpdu, size, 5);
+ g_free (tpdu);
+ if (CAM_FAILED (ret))
+ return ret;
+
+ return CAM_RETURN_OK;
+}
+
+static CamReturn
+handle_open_session_request (CamSL * sl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length)
+{
+ CamReturn ret;
+ guint resource_id;
+ guint status;
+ guint16 session_nb;
+ CamSLSession *session;
+
+ /* SPDU layout (6 bytes):
+ * TAG_OPEN_SESSION_REQUEST (1 byte)
+ * length_field() (1 byte)
+ * resource id (4 bytes)
+ */
+ if (spdu_length != 6) {
+ GST_ERROR ("expected OPEN_SESSION_REQUEST to be 6 bytes, got %d",
+ spdu_length);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ /* skip tag and length_field () */
+ resource_id = GST_READ_UINT32_BE (&spdu[2]);
+
+ /* create a new session */
+ if (sl->session_ids == G_MAXUINT16) {
+ GST_ERROR ("too many sessions opened");
+ return CAM_RETURN_SESSION_TOO_MANY_SESSIONS;
+ }
+
+ session_nb = ++sl->session_ids;
+ session = cam_sl_session_new (sl, connection, session_nb, resource_id);
+
+ GST_INFO ("session request: %d %x", session_nb, session->resource_id);
+
+ if (sl->open_session_request) {
+ /* forward the request to the upper layer */
+ ret = sl->open_session_request (sl, session, &status);
+ if (CAM_FAILED (ret))
+ goto error;
+ } else {
+ status = 0xF0;
+ }
+
+ ret = send_open_session_response (sl, session, (guint8) status);
+ if (CAM_FAILED (ret))
+ goto error;
+
+ GST_INFO ("session request response: %d %x", session_nb, status);
+
+ if (status == CAM_SL_RESOURCE_STATUS_OPEN) {
+ /* if the session has been accepted add it and signal */
+ session->state = CAM_SL_SESSION_STATE_ACTIVE;
+ g_hash_table_insert (sl->sessions,
+ GINT_TO_POINTER ((guint) session_nb), session);
+
+ if (sl->session_opened) {
+ /* notify the upper layer */
+ ret = sl->session_opened (sl, session);
+ if (CAM_FAILED (ret))
+ return ret;
+ }
+ } else {
+ /* session request wasn't accepted */
+ cam_sl_session_destroy (session);
+ }
+
+ return CAM_RETURN_OK;
+
+error:
+ cam_sl_session_destroy (session);
+
+ return ret;
+}
+
+static CamReturn
+handle_create_session_response (CamSL * sl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length)
+{
+ guint8 status;
+ guint resource_id;
+ guint16 session_nb;
+ CamSLSession *session;
+
+ /* SPDU layout (9 bytes):
+ * TAG_CREATE_SESSION_RESPONSE (1 byte)
+ * length_field() (1 byte)
+ * status (1 byte)
+ * resource id (4 bytes)
+ * session number (2 bytes)
+ */
+ if (spdu_length != 9) {
+ GST_ERROR ("expected CREATE_SESSION_RESPONSE to be 9 bytes, got %d",
+ spdu_length);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ /* skip tag and length */
+ status = spdu[2];
+ resource_id = GST_READ_UINT32_BE (&spdu[3]);
+ session_nb = GST_READ_UINT16_BE (&spdu[7]);
+
+ session = g_hash_table_lookup (sl->sessions,
+ GINT_TO_POINTER ((guint) session_nb));
+ if (session == NULL) {
+ GST_DEBUG ("got CREATE_SESSION_RESPONSE for unknown session: %d",
+ session_nb);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ if (session->state == CAM_SL_SESSION_STATE_CLOSING) {
+ GST_DEBUG ("ignoring CREATE_SESSION_RESPONSE for closing session: %d",
+ session_nb);
+ return CAM_RETURN_OK;
+ }
+
+ session->state = CAM_SL_SESSION_STATE_ACTIVE;
+
+ GST_DEBUG ("session opened %d", session->session_nb);
+
+ if (sl->session_opened)
+ /* notify the upper layer */
+ return sl->session_opened (sl, session);
+ return CAM_RETURN_OK;
+}
+
+static CamReturn
+handle_close_session_request (CamSL * sl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length)
+{
+ CamReturn ret;
+ guint16 session_nb;
+ CamSLSession *session;
+ guint8 status = 0;
+
+ /* SPDU layout (4 bytes):
+ * TAG_CLOSE_SESSION_REQUEST (1 byte)
+ * length_field () (1 byte)
+ * session number (2 bytes)
+ */
+ if (spdu_length != 4) {
+ GST_ERROR ("expected CLOSE_SESSION_REQUEST to be 4 bytes, got %d",
+ spdu_length);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ /* skip tag and length_field() */
+ session_nb = GST_READ_UINT16_BE (&spdu[2]);
+
+ GST_DEBUG ("close session request %d", session_nb);
+
+ session = g_hash_table_lookup (sl->sessions,
+ GINT_TO_POINTER ((guint) session_nb));
+ if (session == NULL) {
+ GST_WARNING ("got CLOSE_SESSION_REQUEST for unknown session: %d",
+ session_nb);
+
+ status = 0xF0;
+ } else if (session->state == CAM_SL_SESSION_STATE_CLOSING) {
+ GST_WARNING ("got CLOSE_SESSION_REQUEST for closing session: %d",
+ session_nb);
+
+ status = 0xF0;
+ }
+
+ GST_DEBUG ("close session response: %d %d", session->session_nb, status);
+
+ ret = send_close_session_response (sl, session, status);
+ if (CAM_FAILED (ret))
+ return ret;
+
+ if (session->state != CAM_SL_SESSION_STATE_CLOSING) {
+ GST_DEBUG ("session closed %d", session->session_nb);
+
+ if (sl->session_closed)
+ ret = sl->session_closed (sl, session);
+
+ g_hash_table_remove (sl->sessions,
+ GINT_TO_POINTER ((guint) session->session_nb));
+
+ if (CAM_FAILED (ret))
+ return ret;
+ }
+
+ return CAM_RETURN_OK;
+}
+
+static CamReturn
+handle_close_session_response (CamSL * sl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length)
+{
+ guint16 session_nb;
+ CamSLSession *session;
+ CamReturn ret = CAM_RETURN_OK;
+
+ /* SPDU layout (5 bytes):
+ * TAG_CLOSE_SESSION_RESPONSE (1 byte)
+ * length_field () (1 byte)
+ * status (1 byte)
+ * session number (2 bytes)
+ */
+
+ if (spdu_length != 5) {
+ GST_ERROR ("expected CLOSE_SESSION_RESPONSE to be 5 bytes, got %d",
+ spdu_length);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ /* skip tag, length_field() and session_status */
+ session_nb = GST_READ_UINT16_BE (&spdu[3]);
+
+ session = g_hash_table_lookup (sl->sessions,
+ GINT_TO_POINTER ((guint) session_nb));
+ if (session == NULL || session->state != CAM_SL_SESSION_STATE_ACTIVE) {
+ GST_ERROR ("unexpected CLOSED_SESSION_RESPONSE");
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ GST_DEBUG ("session closed %d", session->session_nb);
+
+ if (sl->session_closed)
+ ret = sl->session_closed (sl, session);
+
+ g_hash_table_remove (sl->sessions,
+ GINT_TO_POINTER ((guint) session->session_nb));
+
+ return ret;
+}
+
+static CamReturn
+handle_session_data (CamSL * sl, CamTLConnection * connection,
+ guint8 * spdu, guint length)
+{
+ guint16 session_nb;
+ CamSLSession *session;
+
+ /* SPDU layout (>= 4 bytes):
+ * TAG_SESSION_NUMBER (1 byte)
+ * length_field() (1 byte)
+ * session number (2 bytes)
+ * one or more APDUs
+ */
+
+ if (length < 4) {
+ GST_ERROR ("invalid SESSION_NUMBER SPDU length %d", length);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ session_nb = GST_READ_UINT16_BE (&spdu[2]);
+
+ session = g_hash_table_lookup (sl->sessions,
+ GINT_TO_POINTER ((guint) session_nb));
+ if (session == NULL) {
+ GST_ERROR ("got SESSION_NUMBER on an unknown connection: %d", session_nb);
+ return CAM_RETURN_SESSION_ERROR;
+ }
+
+ if (sl->session_data)
+ /* pass the APDUs to the upper layer, removing our 4-bytes header */
+ return sl->session_data (sl, session, spdu + 4, length - 4);
+
+ return CAM_RETURN_OK;
+}
+
+static CamReturn
+connection_data_cb (CamTL * tl, CamTLConnection * connection,
+ guint8 * spdu, guint spdu_length)
+{
+ CamReturn ret;
+ CamSL *sl = CAM_SL (tl->user_data);
+
+ switch (spdu[I_TAG]) {
+ case TAG_CREATE_SESSION_RESPONSE:
+ ret = handle_create_session_response (sl, connection, spdu, spdu_length);
+ break;
+ case TAG_OPEN_SESSION_REQUEST:
+ ret = handle_open_session_request (sl, connection, spdu, spdu_length);
+ break;
+ case TAG_CLOSE_SESSION_REQUEST:
+ ret = handle_close_session_request (sl, connection, spdu, spdu_length);
+ break;
+ case TAG_CLOSE_SESSION_RESPONSE:
+ ret = handle_close_session_response (sl, connection, spdu, spdu_length);
+ break;
+ case TAG_SESSION_NUMBER:
+ ret = handle_session_data (sl, connection, spdu, spdu_length);
+ break;
+ default:
+ g_return_val_if_reached (CAM_RETURN_SESSION_ERROR);
+ }
+
+ return ret;
+}