1 /*
2 * camconditionalaccess.c - CAM (EN50221) Conditional Access Resource
3 * Copyright (C) 2007 Alessandro Decina
4 *
5 * Authors:
6 * Alessandro Decina <alessandro.d@gmail.com>
7 *
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.1 of the License, or (at your option) any later version.
12 *
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.
17 *
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., 51 Franklin St, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <unistd.h>
25 #include <string.h>
26 #include "camutils.h"
27 #include "camconditionalaccess.h"
28
29 #define GST_CAT_DEFAULT cam_debug_cat
30 #define TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY 0x9F8030
31 #define TAG_CONDITIONAL_ACCESS_INFO_REPLY 0x9F8031
32 #define TAG_CONDITIONAL_ACCESS_PMT 0x9F8032
33 #define TAG_CONDITIONAL_ACCESS_PMT_REPLY 0x9F8033
34
35 static CamReturn session_request_impl (CamALApplication * application,
36 CamSLSession * session, CamSLResourceStatus * status);
37 static CamReturn open_impl (CamALApplication * application,
38 CamSLSession * session);
39 static CamReturn close_impl (CamALApplication * application,
40 CamSLSession * session);
41 static CamReturn data_impl (CamALApplication * application,
42 CamSLSession * session, guint tag, guint8 * buffer, guint length);
43
44 CamConditionalAccess *
cam_conditional_access_new(void)45 cam_conditional_access_new (void)
46 {
47 CamConditionalAccess *cas;
48 CamALApplication *application;
49
50 cas = g_new0 (CamConditionalAccess, 1);
51
52 application = CAM_AL_APPLICATION (cas);
53 _cam_al_application_init (application);
54 application->resource_id = CAM_AL_CONDITIONAL_ACCESS_ID;
55 application->session_request = session_request_impl;
56 application->open = open_impl;
57 application->close = close_impl;
58 application->data = data_impl;
59
60 cas->ready = FALSE;
61
62 return cas;
63 }
64
65 void
cam_conditional_access_destroy(CamConditionalAccess * cas)66 cam_conditional_access_destroy (CamConditionalAccess * cas)
67 {
68 _cam_al_application_destroy (CAM_AL_APPLICATION (cas));
69 g_free (cas);
70 }
71
72 static CamReturn
send_ca_pmt(CamConditionalAccess * cas,GstMpegtsPMT * pmt,guint8 list_management,guint8 cmd_id)73 send_ca_pmt (CamConditionalAccess * cas, GstMpegtsPMT * pmt,
74 guint8 list_management, guint8 cmd_id)
75 {
76 CamReturn ret;
77 guint8 *buffer;
78 guint buffer_size;
79 guint offset;
80 guint8 *ca_pmt;
81 guint ca_pmt_size;
82 GList *walk;
83
84 ca_pmt = cam_build_ca_pmt (pmt, list_management, cmd_id, &ca_pmt_size);
85 cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al,
86 ca_pmt_size, &buffer_size, &offset);
87
88 buffer = g_malloc0 (buffer_size);
89 memcpy (buffer + offset, ca_pmt, ca_pmt_size);
90
91 for (walk = CAM_AL_APPLICATION (cas)->sessions; walk; walk = walk->next) {
92 CamSLSession *session = CAM_SL_SESSION (walk->data);
93
94 ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
95 TAG_CONDITIONAL_ACCESS_PMT, buffer, buffer_size, ca_pmt_size);
96 if (CAM_FAILED (ret)) {
97 GST_ERROR ("error sending ca_pmt to slot %d, error: %d",
98 session->connection->slot, ret);
99 continue;
100 }
101 }
102
103 g_free (ca_pmt);
104 g_free (buffer);
105
106 return CAM_RETURN_OK;
107 }
108
109 CamReturn
cam_conditional_access_set_pmt(CamConditionalAccess * cas,GstMpegtsPMT * pmt,CamConditionalAccessPmtFlag flag)110 cam_conditional_access_set_pmt (CamConditionalAccess * cas,
111 GstMpegtsPMT * pmt, CamConditionalAccessPmtFlag flag)
112 {
113 return send_ca_pmt (cas, pmt, flag, 0x01 /* ok_descrambling */ );
114 }
115
116 static CamReturn
send_simple(CamConditionalAccess * cas,CamSLSession * session,guint tag)117 send_simple (CamConditionalAccess * cas, CamSLSession * session, guint tag)
118 {
119 guint8 *buffer;
120 guint offset;
121 guint buffer_size;
122 CamReturn ret;
123
124 cam_al_calc_buffer_size (CAM_AL_APPLICATION (cas)->al, 0, &buffer_size,
125 &offset);
126 buffer = g_malloc (buffer_size);
127
128 ret = cam_al_application_write (CAM_AL_APPLICATION (cas), session,
129 tag, buffer, buffer_size, 0);
130
131 g_free (buffer);
132
133 return ret;
134 }
135
136 static CamReturn
send_conditional_access_enquiry(CamConditionalAccess * cas,CamSLSession * session)137 send_conditional_access_enquiry (CamConditionalAccess * cas,
138 CamSLSession * session)
139 {
140 GST_DEBUG ("sending application CAS enquiry");
141 return send_simple (cas, session, TAG_CONDITIONAL_ACCESS_INFO_ENQUIRY);
142 }
143
144 static CamReturn
session_request_impl(CamALApplication * application,CamSLSession * session,CamSLResourceStatus * status)145 session_request_impl (CamALApplication * application,
146 CamSLSession * session, CamSLResourceStatus * status)
147 {
148 *status = CAM_SL_RESOURCE_STATUS_OPEN;
149
150 return CAM_RETURN_OK;
151 }
152
153 static CamReturn
open_impl(CamALApplication * application,CamSLSession * session)154 open_impl (CamALApplication * application, CamSLSession * session)
155 {
156 CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
157
158 GST_INFO ("opening conditional access session %d", session->session_nb);
159
160 return send_conditional_access_enquiry (cas, session);
161 }
162
163 static CamReturn
close_impl(CamALApplication * application,CamSLSession * session)164 close_impl (CamALApplication * application, CamSLSession * session)
165 {
166 GST_INFO ("closing conditional access session %d", session->session_nb);
167
168 return CAM_RETURN_OK;
169 }
170
171 static CamReturn
handle_conditional_access_info_reply(CamConditionalAccess * cas,CamSLSession * session,guint8 * buffer,guint length)172 handle_conditional_access_info_reply (CamConditionalAccess * cas,
173 CamSLSession * session, guint8 * buffer, guint length)
174 {
175 #ifndef GST_DISABLE_GST_DEBUG
176 int i;
177 guint16 cas_id;
178
179 GST_INFO ("conditional access info enquiry reply");
180
181 for (i = 0; i < length / 2; ++i) {
182 cas_id = GST_READ_UINT16_BE (buffer);
183
184 GST_INFO ("slot %d, cas_id 0x%x", session->connection->slot, cas_id);
185
186 buffer += 2;
187 }
188
189 cas->ready = TRUE;
190 #endif
191
192 return CAM_RETURN_OK;
193 }
194
195 static CamReturn
handle_conditional_access_pmt_reply(CamConditionalAccess * cas,CamSLSession * session,guint8 * buffer,guint length)196 handle_conditional_access_pmt_reply (CamConditionalAccess * cas,
197 CamSLSession * session, guint8 * buffer, guint length)
198 {
199 #ifndef GST_DISABLE_GST_DEBUG
200 guint16 program_num;
201 guint8 version_num, current_next_indicator;
202
203 GST_INFO ("conditional access PMT reply");
204
205 program_num = GST_READ_UINT16_BE (buffer);
206 buffer += 2;
207
208 GST_INFO ("program_number : %d", program_num);
209
210 version_num = *buffer >> 1 & 0x1f;
211 current_next_indicator = *buffer & 0x1;
212 buffer++;
213
214 GST_INFO ("version_num:%d, current_next_indicator:%d",
215 version_num, current_next_indicator);
216
217 GST_INFO ("CA_enable : %d (0x%x)", *buffer >> 7 ? *buffer & 0x7f : 0,
218 *buffer);
219 buffer++;
220
221 length -= 4;
222
223 while (length > 0) {
224 guint16 PID = GST_READ_UINT16_BE (buffer);
225 buffer += 2;
226 GST_INFO ("PID 0x%x CA_enable : %d (0x%x)", PID,
227 *buffer >> 7 ? *buffer & 0x7f : 0, *buffer);
228 buffer++;
229
230 length -= 3;
231 }
232 #endif
233
234 return CAM_RETURN_OK;
235 }
236
237 static CamReturn
data_impl(CamALApplication * application,CamSLSession * session,guint tag,guint8 * buffer,guint length)238 data_impl (CamALApplication * application, CamSLSession * session,
239 guint tag, guint8 * buffer, guint length)
240 {
241 CamReturn ret;
242 CamConditionalAccess *cas = CAM_CONDITIONAL_ACCESS (application);
243
244 switch (tag) {
245 case TAG_CONDITIONAL_ACCESS_INFO_REPLY:
246 ret = handle_conditional_access_info_reply (cas, session, buffer, length);
247 break;
248 case TAG_CONDITIONAL_ACCESS_PMT_REPLY:
249 ret = handle_conditional_access_pmt_reply (cas, session, buffer, length);
250 break;
251 default:
252 GST_WARNING ("Got unknown callback, tag 0x%x", tag);
253 g_return_val_if_reached (CAM_RETURN_ERROR);
254 }
255
256 return ret;
257 }
258