2
* camapplication.c - GStreamer CAM (EN50221) Application Layer
3
* Copyright (C) 2007 Alessandro Decina
6
* Alessandro Decina <alessandro@nnva.org>
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Library General Public
10
* License as published by the Free Software Foundation; either
11
* version 2 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Library General Public License for more details.
18
* You should have received a copy of the GNU Library General Public
19
* License along with this library; if not, write to the
20
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21
* Boston, MA 02111-1307, USA.
24
#include "camapplication.h"
26
#define GST_CAT_DEFAULT cam_debug_cat
28
static CamReturn open_session_request_cb (CamSL * sl,
29
CamSLSession * session, CamSLResourceStatus * status);
30
static CamReturn session_opened_cb (CamSL * sl, CamSLSession * session);
31
static CamReturn session_closed_cb (CamSL * sl, CamSLSession * session);
32
static CamReturn session_data_cb (CamSL * sl,
33
CamSLSession * session, guint8 * data, guint length);
36
resource_id_hash (gconstpointer key)
38
guint resource_id = GPOINTER_TO_UINT (key);
40
if (!CAM_AL_RESOURCE_ID_IS_PUBLIC (resource_id)) {
41
/* private identifier, leave it as is */
45
/* public identifier, mask out the version number */
46
return resource_id >> 6;
50
cam_al_new (CamSL * sl)
52
CamAL *al = g_new0 (CamAL, 1);
55
al->applications = g_hash_table_new (resource_id_hash, g_direct_equal);
58
sl->open_session_request = open_session_request_cb;
59
sl->session_opened = session_opened_cb;
60
sl->session_closed = session_closed_cb;
61
sl->session_data = session_data_cb;
67
cam_al_destroy (CamAL * al)
69
g_hash_table_destroy (al->applications);
74
cam_al_install (CamAL * al, CamALApplication * application)
76
if (g_hash_table_lookup (al->applications,
77
GINT_TO_POINTER (application->resource_id)) != NULL)
82
g_hash_table_insert (al->applications,
83
GINT_TO_POINTER (application->resource_id), application);
89
cam_al_uninstall (CamAL * al, CamALApplication * application)
93
ret = g_hash_table_remove (al->applications,
94
GINT_TO_POINTER (application->resource_id));
100
cam_al_get (CamAL * al, guint resource_id)
102
return CAM_AL_APPLICATION (g_hash_table_lookup (al->applications,
103
GINT_TO_POINTER (resource_id)));
107
_cam_al_application_init (CamALApplication * application)
109
application->sessions = NULL;
113
_cam_al_application_destroy (CamALApplication * application)
115
g_list_free (application->sessions);
119
foreach_get_key (gpointer key, gpointer value, gpointer user_data)
121
GList **lst = (GList **) user_data;
123
*lst = g_list_append (*lst, key);
127
cam_al_get_resource_ids (CamAL * al)
129
GList *resource_ids = NULL;
131
g_hash_table_foreach (al->applications, foreach_get_key, &resource_ids);
137
cam_al_calc_buffer_size (CamAL * al, guint body_length,
138
guint * buffer_size, guint * offset)
140
guint apdu_header_length;
141
guint8 length_field_len;
143
/* get the length of the lenght_field() */
144
length_field_len = cam_calc_length_field_size (body_length);
146
/* sum the APDU header */
147
apdu_header_length = 3 + length_field_len;
149
/* chain up to the session layer to get the size of the buffer that can
150
* contain the whole APDU */
151
cam_sl_calc_buffer_size (al->sl, apdu_header_length + body_length,
152
buffer_size, offset);
154
/* add the APDU header to the SPDU offset */
155
*offset += apdu_header_length;
159
cam_al_application_write (CamALApplication * application,
160
CamSLSession * session, guint tag, guint8 * buffer, guint buffer_size,
163
guint length_field_len;
164
guint apdu_header_length;
167
length_field_len = cam_calc_length_field_size (body_length);
168
apdu_header_length = 3 + length_field_len;
169
apdu = (buffer + buffer_size) - body_length - apdu_header_length;
171
apdu[1] = (tag >> 8) & 0xFF;
172
apdu[2] = tag & 0xFF;
174
cam_write_length_field (&apdu[3], body_length);
176
return cam_sl_session_write (session, buffer, buffer_size,
177
apdu_header_length + body_length);
181
open_session_request_cb (CamSL * sl, CamSLSession * session,
182
CamSLResourceStatus * status)
184
CamAL *al = CAM_AL (sl->user_data);
185
CamALApplication *application;
186
guint resource_id = session->resource_id;
189
application = g_hash_table_lookup (al->applications,
190
GINT_TO_POINTER (resource_id));
191
if (application == NULL) {
192
*status = CAM_SL_RESOURCE_STATUS_NOT_FOUND;
194
return CAM_RETURN_OK;
197
if (CAM_AL_RESOURCE_ID_VERSION (application->resource_id)
198
< CAM_AL_RESOURCE_ID_VERSION (resource_id)) {
199
*status = CAM_SL_RESOURCE_STATUS_INVALID_VERSION;
201
return CAM_RETURN_OK;
204
ret = application->session_request (application, session, status);
205
if (CAM_FAILED (ret)) {
206
*status = CAM_SL_RESOURCE_STATUS_NOT_FOUND;
211
if (*status == CAM_SL_RESOURCE_STATUS_OPEN) {
212
session->user_data = application;
213
application->sessions = g_list_append (application->sessions, session);
216
return CAM_RETURN_OK;
220
session_opened_cb (CamSL * sl, CamSLSession * session)
222
CamALApplication *application;
224
application = CAM_AL_APPLICATION (session->user_data);
225
if (application == NULL) {
226
GST_ERROR ("session is established but has no application");
227
return CAM_RETURN_APPLICATION_ERROR;
230
return application->open (application, session);
234
session_closed_cb (CamSL * sl, CamSLSession * session)
236
CamALApplication *application;
240
application = CAM_AL_APPLICATION (session->user_data);
241
if (application == NULL) {
242
GST_ERROR ("session is established but has no application");
243
return CAM_RETURN_APPLICATION_ERROR;
246
ret = application->close (application, session);
247
for (walk = application->sessions; walk; walk = g_list_next (walk)) {
248
CamSLSession *s = CAM_SL_SESSION (walk->data);
250
if (s->session_nb == session->session_nb) {
251
application->sessions = g_list_delete_link (application->sessions, walk);
260
session_data_cb (CamSL * sl, CamSLSession * session, guint8 * data, guint size)
262
CamALApplication *application;
264
guint8 length_field_len;
268
application = CAM_AL_APPLICATION (session->user_data);
269
if (application == NULL) {
270
GST_ERROR ("session is established but has no application");
271
return CAM_RETURN_APPLICATION_ERROR;
275
GST_ERROR ("invalid APDU length %d", size);
276
return CAM_RETURN_APPLICATION_ERROR;
279
for (i = 0; i < 3; ++i)
280
tag = (tag << 8) | data[i];
282
length_field_len = cam_read_length_field (&data[3], &length);
284
if (length != size - 4) {
285
GST_ERROR ("unexpected APDU length %d expected %d", length, size);
287
return CAM_RETURN_APPLICATION_ERROR;
290
return application->data (application, session,
291
tag, data + 3 + length_field_len, length);