1 #define MODULE_LOG_PREFIX "radegast"
5 #include "oscam-client.h"
8 #include "oscam-string.h"
9 #include "oscam-reader.h"
11 static int32_t radegast_connect(void);
13 static int32_t radegast_send(struct s_client
*client
, uchar
*buf
)
15 int32_t l
= buf
[1] + 2;
16 return (send(client
->pfd
, buf
, l
, 0));
19 static int32_t radegast_recv(struct s_client
*client
, uchar
*buf
, int32_t l
)
22 if(!client
->pfd
) { return (-1); }
23 if(client
->typ
== 'c') // server code
25 if((n
= cs_recv(client
->pfd
, buf
, l
, 0)) > 0)
26 { client
->last
= time((time_t *) 0); }
30 if((n
= cs_recv(client
->pfd
, buf
, l
, 0)) > 0)
32 cs_log_dump_dbg(D_CLIENT
, buf
, n
, "radegast: received %d bytes from %s", n
, remote_txt());
33 client
->last
= time((time_t *) 0);
34 if((buf
[0] == 0x02) && (buf
[1] == 0x12) && (buf
[2] == 0x05) && (buf
[3] == 0x10)) { return (n
); } // dcw received
35 else if((buf
[0] == 0x02) && (buf
[1] == 0x02) && (buf
[2] == 0x04) && (buf
[3] == 0x00)) { return (n
); } // dcw no found
36 else if((buf
[0] == 0x81) && (buf
[1] == 0x00)) { return (n
); } // cmd unknown
37 else { n
= -1; }// no cmd radegast disconnect
43 static int32_t radegast_recv_chk(struct s_client
*client
, uchar
*dcw
, int32_t *rc
, uchar
*buf
, int32_t UNUSED(n
))
45 if((buf
[0] == 2) && (buf
[1] == 0x12))
48 memcpy(dcw
, buf
+ 4, 16);
49 cs_log_dbg(D_CLIENT
, "radegast: recv chk - %s", cs_hexdump(0, dcw
, 16, tmp_dbg
, sizeof(tmp_dbg
)));
51 return (client
->reader
->msg_idx
);
57 static void radegast_auth_client(IN_ADDR_T ip
)
60 struct s_auth
*account
;
61 struct s_client
*cl
= cur_client();
63 ok
= check_ip(cfg
.rad_allowed
, ip
);
67 cs_log("radegast: IP not allowed");
68 cs_auth_client(cl
, (struct s_auth
*)0, NULL
);
69 cs_disconnect_client(cl
);
72 for(ok
= 0, account
= cfg
.account
; cfg
.rad_usr
&& account
&& !ok
; account
= account
->next
)
74 ok
= streq(cfg
.rad_usr
, account
->usr
);
75 if(ok
&& cs_auth_client(cl
, account
, NULL
))
76 { cs_disconnect_client(cl
); }
80 { cs_auth_client(cl
, ok
? account
: (struct s_auth
*)(-1), "radegast"); }
83 static void radegast_send_dcw(struct s_client
*client
, ECM_REQUEST
*er
)
86 mbuf
[0] = 0x02; // DCW
87 if(er
->rc
< E_NOTFOUND
)
89 mbuf
[1] = 0x12; // len (overall)
90 mbuf
[2] = 0x05; // ACCESS
91 mbuf
[3] = 0x10; // len
92 memcpy(mbuf
+ 4, er
->cw
, 16);
96 mbuf
[1] = 0x02; // len (overall)
97 mbuf
[2] = 0x04; // NO ACCESS
98 mbuf
[3] = 0x00; // len
100 radegast_send(client
, mbuf
);
103 static void radegast_process_ecm(uchar
*buf
, int32_t l
)
107 struct s_client
*cl
= cur_client();
109 if(!(er
= get_ecmtask()))
111 for(i
= 0; i
+1 < l
; i
+= (sl
+ 2))
117 case 2: // CAID (upper byte only, oldstyle)
120 er
->caid
= buf
[i
+ 2] << 8;
125 er
->caid
= b2i(2, buf
+ i
+ 2);
131 er
->ecmlen
= (((buf
[i
+ 1 + 2] & 0x0F) << 8) | buf
[i
+ 2 + 2]) + 3;
133 if(er
->ecmlen
< 3 || er
->ecmlen
> MAX_ECM_SIZE
|| i
+2+er
->ecmlen
> l
)
136 memcpy(er
->ecm
, buf
+ i
+ 2, er
->ecmlen
);
138 case 6: // PROVID (ASCII)
141 n
= (sl
> 6) ? 3 : (sl
>> 1);
142 er
->prid
= cs_atoi((char *) buf
+ i
+ 2 + sl
- (n
<< 1), n
, 0);
144 case 7: // KEYNR (ASCII), not needed
146 case 8: // ECM PROCESS PID ?? don't know, not needed
151 { cs_log("WARNING: ECM-request corrupt"); }
156 static void radegast_process_unknown(uchar
*buf
)
158 uchar answer
[2] = {0x81, 0x00};
159 radegast_send(cur_client(), answer
);
160 cs_log("unknown request %02X, len=%d", buf
[0], buf
[1]);
163 static void *radegast_server(struct s_client
*client
, uchar
*mbuf
, int32_t n
)
168 if(!client
->init_done
)
170 radegast_auth_client(cur_client()->ip
);
171 client
->init_done
= 1;
177 radegast_process_ecm(mbuf
+ 2, mbuf
[1]);
180 radegast_process_unknown(mbuf
);
186 static int32_t radegast_send_ecm(struct s_client
*client
, ECM_REQUEST
*er
)
189 uchar header
[22] = "\x02\x01\x00\x06\x08\x30\x30\x30\x30\x30\x30\x30\x30\x07\x04\x30\x30\x30\x38\x08\x01\x02";
193 uint8_t *via_ecm_mod
;
194 uint32_t n
, k
, Len
, pos
= 0;
196 if(!radegast_connect())
199 if(!cs_malloc(&ecmbuf
, er
->ecmlen
+ 30))
202 // Quickfix to suppress SubECMs with CWsSwap set to 01
203 // Applied only on Viaccess (CAID: 0x0500)
204 // this reduce the size of the ECM from long to short
205 // 40 07 03 0B 00 08 07 01 00 ... -> to keep
206 // 40 07 03 0B 00 08 07 01 01 ... -> to delete
207 // Thanks to luffy for the tip and the code.
209 if(er
->caid
== 0x500)
211 cs_log_dump_dbg(D_ATR
, er
->ecm
, er
->ecmlen
, "%s: ecm dump BEFORE suppressing SubECMs with CWsSwap set to 01", __func__
);
213 if(cs_malloc (&via_ecm_mod
, Len
+4))
215 if( er
->ecm
[4]==0x80 )
217 memcpy(via_ecm_mod
, er
->ecm
, 4);
218 via_ecm_mod
[1] = 0x70;
219 via_ecm_mod
[2] = 0x01;
224 SubECMp
= (uint8_t *)&er
->ecm
[k
];
225 if( ((pos
+SubECMp
[1]+2)>0xE0)||(pos
+SubECMp
[1]+2)>Len
)
230 if (SubECMp
[2]==0xD2)
232 if( SubECMp
[0x0E] == 0x00 )
234 memcpy(via_ecm_mod
+pos
, SubECMp
, SubECMp
[1]+2);
235 via_ecm_mod
[2] += SubECMp
[1]+2;
239 else if ( (SubECMp
[2]==0x90 || SubECMp
[2]==0x40) && SubECMp
[3]==0x07 )
241 if( SubECMp
[0x0A] == 0x00 || SubECMp
[0x0A] == 0xFF )
243 memcpy(via_ecm_mod
+pos
, SubECMp
, SubECMp
[1]+2);
244 via_ecm_mod
[2] += SubECMp
[1]+2;
250 Len
= via_ecm_mod
[2]+3;
252 memcpy(er
->ecm
, via_ecm_mod
, Len
);
253 cs_log_dump_dbg(D_ATR
, er
->ecm
, er
->ecmlen
, "%s: ecm dump AFTER suppressing SubECMs with CWsSwap set to 01", __func__
);
255 NULLFREE(via_ecm_mod
);
261 ecmbuf
[1] = (er
->ecmlen
+ 30 - 2) & 0xff;
262 memcpy(ecmbuf
+ 2, header
, sizeof(header
));
263 for(n
= 0; n
< 4; n
++)
265 snprintf((char *)provid_buf
+ (n
* 2), sizeof(provid_buf
) - (n
* 2), "%02X", ((uchar
*)(&er
->prid
))[4 - 1 - n
]);
267 ecmbuf
[7] = provid_buf
[0];
268 ecmbuf
[8] = provid_buf
[1];
269 ecmbuf
[9] = provid_buf
[2];
270 ecmbuf
[10] = provid_buf
[3];
271 ecmbuf
[11] = provid_buf
[4];
272 ecmbuf
[12] = provid_buf
[5];
273 ecmbuf
[13] = provid_buf
[6];
274 ecmbuf
[14] = provid_buf
[7];
275 ecmbuf
[2 + sizeof(header
)] = 0xa;
276 ecmbuf
[3 + sizeof(header
)] = 2;
277 ecmbuf
[4 + sizeof(header
)] = er
->caid
>> 8;
278 ecmbuf
[5 + sizeof(header
)] = er
->caid
& 0xff;
279 ecmbuf
[6 + sizeof(header
)] = 3;
280 ecmbuf
[7 + sizeof(header
)] = er
->ecmlen
& 0xff;
281 memcpy(ecmbuf
+ 8 + sizeof(header
), er
->ecm
, er
->ecmlen
);
282 ecmbuf
[4] = er
->caid
>> 8;
284 client
->reader
->msg_idx
= er
->idx
;
285 n
= send(client
->pfd
, ecmbuf
, er
->ecmlen
+ 30, 0);
287 cs_log_dbg(D_TRACE
, "radegast: sending ecm");
288 cs_log_dump_dbg(D_CLIENT
, ecmbuf
, er
->ecmlen
+ 30, "ecm:");
290 return ((n
< 1) ? (-1) : 0);
293 int32_t radegast_cli_init(struct s_client
*cl
)
297 handle
= network_tcp_connection_open(cl
->reader
);
298 if(handle
< 0) { return -1; }
300 cs_log("radegast: proxy %s:%d (fd=%d)",
301 cl
->reader
->device
, cl
->reader
->r_port
, cl
->udp_fd
);
303 cl
->reader
->tcp_connected
= 2;
304 cl
->reader
->card_status
= CARD_INSERTED
;
305 cl
->reader
->last_g
= cl
->reader
->last_s
= time((time_t *)0);
307 cs_log_dbg(D_CLIENT
, "radegast: last_s=%ld, last_g=%ld", cl
->reader
->last_s
, cl
->reader
->last_g
);
309 cl
->pfd
= cl
->udp_fd
;
314 static void radegast_server_init(struct s_client
*cl
)
319 { cs_log("radegast: new connection from %s", cs_inet_ntoa(cl
->ip
)); }
320 radegast_auth_client(cur_client()->ip
);
326 static int32_t radegast_connect(void)
328 struct s_client
*cl
= cur_client();
330 if(cl
->reader
->tcp_connected
< 2 && radegast_cli_init(cl
) < 0)
339 void radegast_idle(void)
341 struct s_client
*client
= cur_client();
342 struct s_reader
*rdr
= client
->reader
;
343 time_t now
= time(NULL
);
349 time_diff
= llabs(now
- rdr
->last_s
);
350 if(time_diff
> (rdr
->tcp_ito
))
352 network_tcp_connection_close(rdr
, "inactivity");
356 else if(rdr
->tcp_ito
== -1)
363 void module_radegast(struct s_module
*ph
)
366 ph
->ptab
.ports
[0].s_port
= cfg
.rad_port
;
368 ph
->desc
= "radegast";
369 ph
->type
= MOD_CONN_TCP
;
370 ph
->large_ecm_support
= 1;
371 ph
->listenertype
= LIS_RADEGAST
;
372 IP_ASSIGN(ph
->s_ip
, cfg
.rad_srvip
);
373 ph
->s_handler
= radegast_server
;
374 ph
->s_init
= radegast_server_init
;
375 ph
->c_idle
= radegast_idle
;
376 ph
->recv
= radegast_recv
;
377 ph
->send_dcw
= radegast_send_dcw
;
378 ph
->c_init
= radegast_cli_init
;
379 ph
->c_recv_chk
= radegast_recv_chk
;
380 ph
->c_send_ecm
= radegast_send_ecm
;
381 ph
->num
= R_RADEGAST
;