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