source: trunk/module-serial.c@ 109

Last change on this file since 109 was 70, checked in by rorothetroll, 11 years ago

csctapi/io_serial.c : fix the serial port read/write wait routine to use select instead of poll

This make them compatible with Mac OS X and now oscamd works on OS X. The same code off course
still works on linux and other unix platforms. I let that code ran for 24h before commiting this code.
If you have any issue let me know and I'llr evert to poll for non compatible machines.

all the others : fix all the warning due to sign difference (mostly uchar versus char). This make the code compile

with -Werror on the more strict version of gcc (which is the case on OS X). I also noticed that in a lot of places
the code use a buffer defined as an uchar * ... and use strings functions (strnXXXX) where some memcpy/memcmp .. function
would have been preferable as we're suposedly manipulation a binary buffer. Anyway I fixed all of them and it now compile
without any warning or error on linux and OS X (and also probably on all the other unices but we will have to try before
adding -Werror on the other platform).

File size: 25.9 KB
Line 
1#include "globals.h"
2#include <termios.h>
3
4#define HSIC_CRC 0xA5
5#define SSSP_MAX_PID 8
6
7#define P_HSIC 1 // Humax Sharing Interface Client
8#define P_SSSP 2 // Simple Serial Sharing Protocol
9#define P_BOMBA 3 // This is not really a Protocol
10#define P_DSR95 4 // DSR9500 with SID
11#define P_GS 5 // GS7001
12#define P_ALPHA 6 // AlphaStar Receivers
13#define P_DSR95_OLD 7 // DSR9500 without SID
14#define P_GBOX 8 // Arion with gbox
15#define P_MAX P_GBOX
16#define P_AUTO 0xFF
17
18#define P_DSR_AUTO 0
19#define P_DSR_GNUSMAS 1
20#define P_DSR_OPEN 2
21#define P_DSR_PIONEER 3
22#define P_DSR_WITHSID 4
23#define P_DSR_UNKNOWN 5
24
25#define IS_ECM 0 // incoming data is ECM
26#define IS_DCW 1 // incoming data is DCW
27#define IS_PMT 2 // incoming data is PMT
28#define IS_LGO 3 // incoming data is client logon
29#define IS_ECHO 4 // incoming data is DCW echo from Samsung
30#define IS_CAT 5 // incoming data is CAT
31#define IS_BAD 0xFF // incoming data is unknown
32
33static char *proto_txt[]={"unknown", "hsic", "sssp", "bomba", "dsr9500", "gs",
34 "alpha", "dsr9500old", "gbox"};
35static char *dsrproto_txt[]={"unknown", "samsung", "openbox", "pioneer",
36 "extended", "unknown"};
37static char *incomplete="incomplete request (%d bytes)";
38static int connected=0;
39static struct timeb tps, tpe;
40static char oscam_ser_usr[32]={0};
41static char oscam_ser_device[64]={0};
42static speed_t oscam_ser_baud=0;
43static int oscam_ser_delay=0;
44static int oscam_ser_timeout=50;
45static int oscam_ser_proto=0;
46int serial_errors=0;
47static int dsr9500type=P_DSR_AUTO;
48static int samsung_0a=0; // number of 0A in ALL dcw sent into samsung
49static int samsung_dcw=0; // number of dcw sent into samsung before echo or ecm is received
50
51typedef struct s_gbox
52{
53 int cat_len;
54 int pmt_len;
55 int ecm_len;
56} GBOX_LENS;
57
58typedef struct s_sssp
59{
60 ushort caid;
61 ushort pid;
62 ulong prid;
63} SSSP_TAB;
64
65
66GBOX_LENS gbox_lens;
67SSSP_TAB sssp_tab[SSSP_MAX_PID];
68ushort sssp_srvid;
69int sssp_num=0, sssp_fix=0;
70
71static int oscam_ser_alpha_convert(uchar *buf, int l)
72{
73 int i;
74 if (buf[0]==0x7E) // normalize
75 {
76 l-=2;
77 memmove(buf, buf+1, l); // remove BOT/EOT
78 for (i=0; i<l; i++)
79 if (buf[i]==0x20)
80 {
81 memmove(buf+i, buf+i+1, --l);
82 buf[i]^=0x20;
83 }
84 }
85 else // to alphastar
86 {
87 memmove(buf+1, buf, l++); // insert BOT
88 buf[0]=0x7E;
89 for (i=1; i<l; i++)
90 if ((buf[i]==0x20) || (buf[i]==0x7E) || (buf[i]==0x7F))
91 {
92 buf[i]^=0x20;
93 memmove(buf+i+1, buf+i, l++);
94 buf[i++]=0x20;
95 }
96 buf[l++]=0x7F; // insert EOT
97 }
98 return(l);
99}
100
101static void oscam_ser_disconnect(void);
102
103static int oscam_ser_parse_url(char *url)
104{
105 char *service, *usr, *dev, *baud=NULL, *dummy, *para;
106
107 oscam_ser_proto=P_AUTO;
108 if( (dummy=strstr(url, "://")) )
109 {
110 int i;
111 service=url;
112 url=dummy+3;
113 *dummy=0;
114 for (i=1; i<=P_MAX; i++)
115 if (!strcmp(service, proto_txt[i]))
116 oscam_ser_proto=i;
117 }
118 if ((!is_server) && (oscam_ser_proto==P_AUTO)) return(0);
119 switch(oscam_ser_proto) // set the defaults
120 {
121 case P_GS:
122 oscam_ser_timeout=500;
123 oscam_ser_baud=B19200;
124 break;
125 default:
126 oscam_ser_timeout=50;
127#ifdef B115200
128 oscam_ser_baud=B115200;
129#else
130 oscam_ser_baud=B9600;
131#endif
132 }
133
134 switch( oscam_ser_proto )
135 {
136 case P_DSR95:
137 dsr9500type=(is_server)?P_DSR_AUTO:P_DSR_WITHSID;
138 break;
139 case P_DSR95_OLD:
140 dsr9500type=P_DSR_AUTO;
141 oscam_ser_proto=P_DSR95;
142 }
143
144 usr=url;
145 if( (dev=strchr(usr, '@')) )
146 {
147 *dev++='\0';
148 if( (dummy=strchr(usr, ':')) ) // fake pwd
149 *dummy++='\0';
150 if ((is_server) && (!usr[0])) return(0);
151 }
152 else
153 {
154 if (is_server) return(0); // user needed in server-mode
155 dev=usr;
156 }
157 if( (baud=strchr(dev, ':')) )// port = baud
158 *baud++='\0';
159 dummy=baud ? baud : dev;
160 if( (para=strchr(dummy, '?')) )
161 {
162 char *ptr1, *ptr2;
163 *para++='\0';
164 for (ptr1=strtok(para, "&"); ptr1; ptr1=strtok(NULL, "&"))
165 {
166 if (!(ptr2=strchr(ptr1, '='))) continue;
167 *ptr2++='\0';
168 strtolower(ptr1);
169 if (!strcmp("delay" , ptr1)) oscam_ser_delay =atoi(ptr2);
170 if (!strcmp("timeout", ptr1)) oscam_ser_timeout=atoi(ptr2);
171 }
172 }
173 if (baud)
174 {
175 trim(baud);
176#ifdef B115200
177 if (!strcmp(baud, "115200"))
178 oscam_ser_baud=B115200;
179 else
180#endif
181#ifdef B57600
182 if (!strcmp(baud, "57600"))
183 oscam_ser_baud=B57600;
184 else
185#endif
186 if (!strcmp(baud, "38400"))
187 oscam_ser_baud=B38400;
188 else if (!strcmp(baud, "19200"))
189 oscam_ser_baud=B19200;
190 else if (!strcmp(baud, "9600"))
191 oscam_ser_baud=B9600;
192 }
193 strncpy(oscam_ser_usr, usr, sizeof(oscam_ser_usr)-1);
194 strncpy(oscam_ser_device, dev, sizeof(oscam_ser_device)-1);
195 return(oscam_ser_baud);
196}
197
198static void oscam_ser_set_baud(struct termios *tio, speed_t baud)
199{
200 cfsetospeed(tio, baud);
201 cfsetispeed(tio, baud);
202}
203
204static int oscam_ser_set_serial_device(int fd)
205{
206 struct termios tio;
207
208 memset(&tio, 0, sizeof(tio));
209 // tio.c_cflag = (CS8 | CREAD | HUPCL | CLOCAL);
210 tio.c_cflag = (CS8 | CREAD | CLOCAL);
211 tio.c_iflag = IGNPAR;
212 tio.c_cc[VMIN] = 1;
213 tio.c_cc[VTIME] = 0;
214//#if !defined(OS_CYGWIN32)
215 oscam_ser_set_baud(&tio, B1200);
216 tcsetattr(fd, TCSANOW, &tio);
217 cs_sleepms(500);
218//#endif
219 oscam_ser_set_baud(&tio, oscam_ser_baud);
220 return(tcsetattr(fd, TCSANOW, &tio));
221}
222
223static int oscam_ser_poll(int event)
224{
225 int msec;
226 struct pollfd pfds;
227 struct timeb tpc;
228 cs_ftime(&tpc);
229 msec=1000*(tpe.time-tpc.time)+tpe.millitm-tpc.millitm;
230 if (msec<0)
231 return(0);
232 pfds.fd=pfd;
233 pfds.events=event;
234 pfds.revents=0;
235 if (poll(&pfds, 1, msec)!=1)
236 return(0);
237 else
238 return(((pfds.revents)&event)==event);
239}
240
241static int oscam_ser_write(uchar *buf, int n)
242{
243 int i;
244 for (i=0; (i<n) && (oscam_ser_poll(POLLOUT)); i++)
245 {
246 if (oscam_ser_delay)
247 cs_sleepms(oscam_ser_delay);
248 if (write(pfd, buf+i, 1)<1)
249 break;
250 }
251 return(i);
252}
253
254static int oscam_ser_send(uchar *buf, int l)
255{
256 int n;
257 if (!pfd) return(0);
258 cs_ftime(&tps);
259 tpe=tps;
260 tpe.millitm+=oscam_ser_timeout+(l*(oscam_ser_delay+1));
261 tpe.time+=(tpe.millitm/1000);
262 tpe.millitm%=1000;
263 n=oscam_ser_write(buf, l);
264 cs_ftime(&tpe);
265 cs_ddump(buf, l, "send %d of %d bytes to %s in %d msec", n, l, remote_txt(),
266 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
267 if (n!=l)
268 cs_log("transmit error. send %d of %d bytes only !", n, l);
269 return(n);
270}
271
272static int oscam_ser_selrec(uchar *buf, int n, int l, int *c)
273{
274 int i;
275 if (*c+n>l)
276 n=l-*c;
277 if (n<=0) return(0);
278 for (i=0; (i<n) && (oscam_ser_poll(POLLIN)); i++)
279 if (read(pfd, buf+*c, 1)<1 )
280 return(0);
281 else
282 (*c)++;
283 return(i==n);
284}
285
286static int oscam_ser_recv(uchar *xbuf, int l)
287{
288 int s, p, n, r;
289 uchar job=IS_BAD;
290 static uchar lb;
291 static int have_lb=0;
292 uchar *buf=xbuf+1;
293
294 if (!pfd) return(-1);
295 cs_ftime(&tps);
296 tpe=tps;
297 tpe.millitm+=oscam_ser_timeout;
298 tpe.time+=(tpe.millitm/1000);
299 tpe.millitm%=1000;
300 buf[0]=lb;
301 for (s=p=r=0, n=have_lb; (s<4) && (p>=0); s++)
302 {
303 switch(s)
304 {
305 case 0: // STAGE 0: skip known garbage from DSR9500
306 if (oscam_ser_selrec(buf, 2-n, l, &n))
307 {
308 if ((buf[0]==0x0A) && (buf[1]==0x0D))
309 p=(-4);
310 if ((buf[0]==0x0D) && (buf[1]==0x0A))
311 p=(-4);
312 }
313 else
314 p=(-3);
315 have_lb=0;
316 break;
317 case 1: // STAGE 1: identify protocol
318 p=(-3);
319 if (oscam_ser_selrec(buf, 1, l, &n)) // now we have 3 bytes in buf
320 {
321 p=(-2);
322 if (is_server) // HERE IS SERVER
323 {
324 job=IS_ECM; // assume ECM
325 switch(buf[0])
326 {
327 case 0x00: if( (buf[1]==0x01)&&(buf[2]==0x00) )
328 { p=P_GS; job=IS_LGO; tpe.time++; } break;
329 case 0x01: if( (buf[1]&0xf0)==0xb0 ) p=P_GBOX;
330 else {p=P_SSSP; job=IS_PMT;}
331 break; // pmt-request
332 case 0x02: p=P_HSIC; break;
333 case 0x03: switch(oscam_ser_proto)
334 {
335 case P_SSSP :
336 case P_GS :
337 case P_DSR95 : p=oscam_ser_proto; break;
338 case P_AUTO : p=(buf[1]<0x30) ? P_SSSP : P_DSR95;
339 break; // auto for GS is useless !!
340 } break;
341 case 0x04: p=P_DSR95; job=IS_ECHO; dsr9500type=P_DSR_GNUSMAS; break;
342 case 0x7E: p=P_ALPHA; if (buf[1]!=0x80) job=IS_BAD; break;
343 case 0x80:
344 case 0x81: p=P_BOMBA; break;
345 }
346 }
347 else // HERE IS CLIENT
348 {
349 job=IS_DCW; // assume DCW
350 switch(oscam_ser_proto)
351 {
352 case P_HSIC : if ((buf[0]==4) && (buf[1]==4)) p=P_HSIC; break;
353 case P_BOMBA: p=P_BOMBA; break;
354 case P_DSR95: if (buf[0]==4) p=P_DSR95; break;
355 case P_ALPHA: if (buf[0]==0x88) p=P_ALPHA; break;
356 }
357 }
358 if ((oscam_ser_proto!=p) && (oscam_ser_proto!=P_AUTO))
359 p=(-2);
360 }
361 break;
362 case 2: // STAGE 2: examine length
363 if (is_server) switch(p)
364 {
365 case P_SSSP : r=(buf[1]<<8)|buf[2]; break;
366 case P_BOMBA : r=buf[2]; break;
367 case P_HSIC : if (oscam_ser_selrec(buf, 12, l, &n)) r=buf[14];
368 else p=(-1);
369 break;
370 case P_DSR95 : if( job==IS_ECHO )
371 {
372 r=17*samsung_dcw-3+samsung_0a;
373 samsung_dcw=samsung_0a=0;
374 }
375 else
376 {
377 if (oscam_ser_selrec(buf, 16, l, &n))
378 {
379 uchar b;
380 if (cs_atob(&b, (char *)buf+17, 1)<0)
381 p=(-2);
382 else {
383 r=(b<<1);
384 r+=(dsr9500type==P_DSR_WITHSID)?4:0;
385 }
386 }
387 else p=(-1);
388 }
389 break;
390 case P_GS : if (job==IS_LGO)
391 r=5;
392 else
393 {
394 if (oscam_ser_selrec(buf, 1, l, &n))
395 r=(buf[3]<<8)|buf[2];
396 else p=(-1);
397 }
398 break;
399 case P_ALPHA : r=-0x7F; // char specifying EOT
400 break;
401 case P_GBOX : r=((buf[1]&0xf)<<8) | buf[2];
402 gbox_lens.cat_len = r;
403 break;
404 default : dsr9500type=P_DSR_AUTO;
405 }
406 else switch(p)
407 {
408 case P_HSIC : r=(buf[2]==0x3A) ? 20 : 0; break; // 3A=DCW / FC=ECM was wrong
409 case P_BOMBA : r=13; break;
410 case P_DSR95 : r=14; break;
411 case P_ALPHA : r=(buf[1]<<8)|buf[2]; break; // should be 16 always
412 }
413 break;
414 case 3: // STAGE 3: get the rest ...
415 if (r>0) // read r additional bytes
416 {
417 int all = n+r;
418 if( !oscam_ser_selrec(buf, r, l, &n) )
419 {
420 cs_debug("not all data received, waiting another 50 ms");
421 tpe.millitm+=50;
422 if( !oscam_ser_selrec(buf, all-n, l, &n) )
423 p=(-1);
424 }
425 // auto detect DSR9500 protocol
426 if( is_server && p==P_DSR95 && dsr9500type==P_DSR_AUTO )
427 {
428 tpe.millitm+=20;
429 if( oscam_ser_selrec(buf, 2, l, &n) )
430 {
431 if( cs_atoi((char *)buf+n-2, 1, 1)==0xFFFFFFFF )
432 {
433 switch( (buf[n-2]<<8)|buf[n-1] )
434 {
435 case 0x0A0D : dsr9500type=P_DSR_OPEN; break;
436 case 0x0D0A : dsr9500type=P_DSR_PIONEER; break;
437 default : dsr9500type=P_DSR_UNKNOWN; break;
438 }
439 }else{
440 if( oscam_ser_selrec(buf, 2, l, &n) )
441 if( cs_atoi((char *)buf+n-2, 1, 1)==0xFFFFFFFF )
442 dsr9500type=P_DSR_UNKNOWN;
443 else
444 dsr9500type=P_DSR_WITHSID;
445 else {
446 dsr9500type=P_DSR_UNKNOWN;
447 p=(-1);
448 }
449 }
450 }
451 else
452 dsr9500type=P_DSR_GNUSMAS;
453 if( p )
454 cs_log("detected dsr9500-%s type receiver",
455 dsrproto_txt[dsr9500type]);
456 }
457 // gbox
458 if( is_server && p==P_GBOX )
459 {
460 int j;
461 for( j=0; (j<3) && (p>0); j++)
462 switch( j )
463 {
464 case 0: // PMT head
465 if( !oscam_ser_selrec(buf, 3, l, &n) )
466 p=(-1);
467 else if( !(buf[n-3]==0x02 && (buf[n-2]&0xf0)==0xb0) )
468 p=(-2);
469 break;
470 case 1: // PMT + ECM header
471 gbox_lens.pmt_len=((buf[n-2]&0xf)<<8)|buf[n-1];
472 if( !oscam_ser_selrec(buf, gbox_lens.pmt_len+3, l, &n) )
473 p=(-1);
474 break;
475 case 2: // ECM + ECM PID
476 gbox_lens.ecm_len=((buf[n-2]&0xf)<<8)|buf[n-1];
477 if( !oscam_ser_selrec(buf, gbox_lens.ecm_len+4, l, &n) )
478 p=(-1);
479 }
480 } // gbox
481 }
482 else if (r<0) // read until specified char (-r)
483 {
484 while((buf[n-1]!=(-r)) && (p>0))
485 if (!oscam_ser_selrec(buf, 1, l, &n))
486 p=(-1);
487 }
488 break;
489 }
490 }
491 if (p==(-2) || p==(-1)) {
492 oscam_ser_selrec(buf, l-n, l, &n); // flush buffer
493 serial_errors++;
494 }
495 cs_ftime(&tpe);
496 cs_ddump(buf, n, "received %d bytes from %s in %d msec", n, remote_txt(),
497 1000*(tpe.time-tps.time)+tpe.millitm-tps.millitm);
498 client[cs_idx].last=tpe.time;
499 switch(p)
500 {
501 case (-1): if (is_server&&(n>2)&&(buf[0]==2)&&(buf[1]==2)&&(buf[2]==2))
502 {
503 oscam_ser_disconnect();
504 cs_log("humax powered on"); // this is nice ;)
505 }
506 else
507 cs_log(incomplete, n);
508 break;
509 case (-2): cs_debug("unknown request or garbage");
510 break;
511 }
512 xbuf[0]=(uchar) ((job<<4) | p);
513 return((p<0)?0:n+1);
514}
515
516/*
517 * server functions
518 */
519
520static void oscam_ser_disconnect_client()
521{
522 switch(connected ? connected : oscam_ser_proto)
523 {
524 case P_GS:
525 mbuf[0] = 0x01;
526 mbuf[1] = 0x00;
527 mbuf[2] = 0x00;
528 mbuf[3] = 0x00;
529 oscam_ser_send(mbuf, 4);
530 break;
531 }
532 dsr9500type=P_DSR_AUTO;
533 serial_errors=0;
534}
535
536static void oscam_ser_init_client()
537{
538 switch(oscam_ser_proto) // sure, does not work in auto-mode
539 {
540 case P_GS:
541 oscam_ser_disconnect_client(); // send disconnect first
542 cs_sleepms(300); // wait a little bit
543 mbuf[0] = 0x00;
544 mbuf[1] = 0x00;
545 mbuf[2] = 0x00;
546 mbuf[3] = 0x00;
547 oscam_ser_send(mbuf, 4); // send connect
548 break;
549 }
550}
551
552static void oscam_ser_disconnect()
553{
554 oscam_ser_disconnect_client();
555 if (connected)
556 cs_log("%s disconnected (%s)", username(cs_idx), proto_txt[connected]);
557 connected=0;
558}
559
560static void oscam_ser_auth_client(int proto)
561{
562 int ok;
563 // After reload base account ptrs may be placed in other address,
564 // and we may can't find it in this process.
565 // Simply save valid account.
566 static struct s_auth *account=0;
567
568 if (connected==proto)
569 return;
570 if (connected)
571 oscam_ser_disconnect();
572 connected=proto;
573 if( !account )
574 {
575 client[cs_idx].usr[0]=0;
576 for (ok=0, account=cfg->account; (account) && (!ok); account=account->next)
577 if( (ok=!strcmp(oscam_ser_usr, account->usr)) )
578 break;
579 }
580 cs_auth_client(ok ? account : (struct s_auth *)(-1), proto_txt[connected]);
581}
582
583static void oscam_ser_send_dcw(ECM_REQUEST *er)
584{
585 int i;
586 uchar crc;
587 if (er->rc<4) // found
588 switch(connected)
589 {
590 case P_HSIC:
591 for (i=0, crc=HSIC_CRC; i<16; i++)
592 crc^=er->cw[i];
593 memset(mbuf , 0x04 , 2);
594 memset(mbuf+2 , 0x3a , 2);
595 memcpy(mbuf+4 , er->cw, 16);
596 memcpy(mbuf+20, &crc , 1);
597 memset(mbuf+21, 0x1b , 2);
598 oscam_ser_send(mbuf, 23);
599 break;
600 case P_SSSP:
601 mbuf[0]=0xF2;
602 mbuf[1]=0;
603 mbuf[2]=16;
604 memcpy(mbuf+3, er->cw, 16);
605 oscam_ser_send(mbuf, 19);
606 if (!sssp_fix)
607 {
608 mbuf[0]=0xF1;
609 mbuf[1]=0;
610 mbuf[2]=2;
611 memcpy(mbuf+3, i2b(2, er->pid), 2);
612 oscam_ser_send(mbuf, 5);
613 sssp_fix=1;
614 }
615 break;
616 case P_GBOX:
617 case P_BOMBA:
618 oscam_ser_send(er->cw, 16);
619 break;
620 case P_DSR95:
621 mbuf[0]=4;
622 memcpy(mbuf+1, er->cw, 16);
623 oscam_ser_send(mbuf, 17);
624 if( dsr9500type==P_DSR_GNUSMAS )
625 {
626 int i;
627 samsung_0a=0;
628 for( i=1; i<17; i++ )
629 if( mbuf[i]==0x0A )
630 samsung_0a++;
631 samsung_dcw++;
632 }
633 break;
634 case P_GS:
635 mbuf[0]=0x03;
636 mbuf[1]=0x08;
637 mbuf[2]=0x10;
638 mbuf[3]=0x00;
639 memcpy(mbuf+4, er->cw, 16);
640 oscam_ser_send(mbuf, 20);
641 break;
642 case P_ALPHA:
643 mbuf[0]=0x88;
644 mbuf[1]=0x00;
645 mbuf[2]=0x10;
646 memcpy(mbuf+3, er->cw, 16);
647 oscam_ser_send(mbuf, 19);
648 break;
649 }
650 else // not found
651 switch(connected)
652 {
653 case P_GS:
654 mbuf[0]=0x03;
655 mbuf[1]=0x09;
656 mbuf[2]=0x00;
657 mbuf[3]=0x00;
658 oscam_ser_send(mbuf, 4);
659 break;
660 }
661 serial_errors=0; // clear error counter
662}
663
664static void oscam_ser_process_pmt(uchar *buf, int l)
665{
666 int i;
667 uchar sbuf[32];
668
669 switch(connected)
670 {
671 case P_SSSP:
672 sssp_fix=0;
673 memset(sssp_tab, 0, sizeof(sssp_tab));
674 sssp_srvid=b2i(2, buf+3);
675 for (i=9, sssp_num=0; (i<l) && (sssp_num<SSSP_MAX_PID); i+=7, sssp_num++)
676 {
677 memcpy(sbuf+3+(sssp_num<<1), buf+i+2, 2);
678 sssp_tab[sssp_num].caid=b2i(2, buf+i );
679 sssp_tab[sssp_num].pid =b2i(2, buf+i+2);
680 sssp_tab[sssp_num].prid=b2i(3, buf+i+4);
681 }
682 sbuf[0]=0xF1;
683 sbuf[1]=0;
684 sbuf[2]=(sssp_num<<1);
685 oscam_ser_send(sbuf, sbuf[2]+3);
686 break;
687 }
688}
689
690static void oscam_ser_client_logon(uchar *buf, int l)
691{
692 uchar gs_logon[]={0, 1, 0, 0, 2, 1, 0, 0};
693 switch(connected)
694 {
695 case P_GS:
696 if ((l>=8) && (!memcmp(buf, gs_logon, 8)))
697 {
698 buf[0] = 0x02;
699 buf[1] = 0x04;
700 buf[2] = 0x00;
701 buf[3] = 0x00;
702 oscam_ser_send(buf, 4);
703 }
704 break;
705 }
706}
707
708static int oscam_ser_check_ecm(ECM_REQUEST *er, uchar *buf, int l)
709{
710 int i;
711
712 if (l<16)
713 {
714 cs_log(incomplete, l);
715 return(1);
716 }
717
718 switch(connected)
719 {
720 case P_HSIC:
721 er->l = l-12;
722 er->caid = b2i(2, buf+1 );
723 er->prid = b2i(3, buf+3 );
724 er->pid = b2i(2, buf+6 );
725 er->srvid= b2i(2, buf+10);
726 memcpy(er->ecm, buf+12, er->l);
727 break;
728 case P_SSSP:
729 er->pid=b2i(2, buf+3);
730 for (i=0; (i<8) && (sssp_tab[i].pid!=er->pid); i++);
731 if (i>=sssp_num)
732 {
733 cs_debug("illegal request, unknown pid=%04X", er->pid);
734 return(2);
735 }
736 er->l = l-5;
737 er->srvid= sssp_srvid;
738 er->caid = sssp_tab[i].caid;
739 er->prid = sssp_tab[i].prid;
740 memcpy(er->ecm, buf+5, er->l);
741 break;
742 case P_BOMBA:
743 er->l=l;
744 memcpy(er->ecm, buf, er->l);
745 break;
746 case P_DSR95:
747 buf[l]='\0'; // prepare for trim
748 trim((char *)buf+13); // strip spc, nl, cr ...
749 er->l=strlen((char *)buf+13)>>1;
750 er->prid=cs_atoi((char *)buf+3, 3, 0); // ignore errors
751 er->caid=cs_atoi((char *)buf+9, 2, 0); // ignore errors
752 if (cs_atob(er->ecm, (char *)buf+13, er->l)<0)
753 {
754 cs_log("illegal characters in ecm-request");
755 return(1);
756 }
757 if( dsr9500type==P_DSR_WITHSID )
758 {
759 er->l-=2;
760 er->srvid=cs_atoi((char *)buf+13+(er->l<<1), 2, 0);
761 }
762 break;
763 case P_GS:
764 er->l = ((buf[3]<<8)|buf[2]) - 6;
765 er->srvid = (buf[5]<<8)|buf[4]; // sid
766 er->caid = (buf[7]<<8)|buf[6];
767 er->prid = 0;
768 if (er->l>256) er->l=256;
769 memcpy(er->ecm, buf+10, er->l);
770 break;
771 case P_ALPHA:
772 l=oscam_ser_alpha_convert(buf, l);
773 er->l = b2i(2, buf+1 )-2;
774 er->caid = b2i(2, buf+3 );
775 if ((er->l!=l-5) || (er->l>257))
776 {
777 cs_log(incomplete, l);
778 return(1);
779 }
780 memcpy(er->ecm, buf+5, er->l);
781 break;
782 case P_GBOX:
783 er->srvid = b2i(2, buf+gbox_lens.cat_len+3+3);
784 er->l = gbox_lens.ecm_len+3;
785 memcpy(er->ecm, buf+gbox_lens.cat_len+3+gbox_lens.pmt_len+3, er->l);
786 break;
787 }
788 return(0);
789}
790
791static void oscam_ser_process_ecm(uchar *buf, int l)
792{
793 ECM_REQUEST *er;
794
795 if (!(er=get_ecmtask()))
796 return;
797
798 switch(oscam_ser_check_ecm(er, buf, l))
799 {
800 case 2: er->rc=9; return; // error without log
801 case 1: er->rc=9; // error with log
802 }
803 get_cw(er);
804}
805
806
807static void oscam_ser_server()
808{
809 int n;
810
811 connected=0;
812 oscam_ser_init_client();
813
814 while ((n=process_input(mbuf, sizeof(mbuf), cfg->cmaxidle))>=0)
815 {
816 if (serial_errors > 3)
817 {
818 cs_log("too many errors, reiniting...");
819 break;
820 }
821 if (n>0)
822 {
823 oscam_ser_auth_client(mbuf[0] & 0xF);
824 switch (mbuf[0]>>4)
825 {
826 case IS_ECM:
827 oscam_ser_process_ecm(mbuf+1, n-1);
828 break;
829 case IS_PMT:
830 oscam_ser_process_pmt(mbuf+1, n-1);
831 break;
832 case IS_LGO:
833 oscam_ser_client_logon(mbuf+1, n-1);
834 break;
835 }
836 }
837 }
838 oscam_ser_disconnect();
839}
840
841static int init_oscam_ser_device(char *device)
842{
843 int fd;
844
845 fd=open(device, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK);
846 if (fd>0)
847 {
848 fcntl(fd, F_SETFL, 0);
849 if (oscam_ser_set_serial_device(fd)<0) cs_log("ERROR ioctl");
850 if (tcflush(fd, TCIOFLUSH)<0) cs_log("ERROR flush");
851 }
852 else
853 {
854 fd=0;
855 cs_log("ERROR opening %s", device);
856 }
857 return(fd);
858}
859
860static void oscam_ser_fork(int idx, char *url)
861{
862 static char logtxt[32];
863
864 is_server=1;
865 if ((!url) || (!url[0])) return;
866 if (!oscam_ser_parse_url(url)) return;
867 snprintf(logtxt, sizeof(logtxt)-1, ", %s@%s",
868 oscam_ser_proto>P_MAX ? "auto" : proto_txt[oscam_ser_proto], oscam_ser_device);
869 ph[idx].logtxt=logtxt;
870 switch(cs_fork(0, idx))
871 {
872 case 0: // master
873 case -1:
874 return;
875 default:
876 wait4master();
877 }
878 while(1)
879 {
880 client[cs_idx].au=(-1);
881 client[cs_idx].usr[0]='\0';
882 client[cs_idx].login=time((time_t *)0);
883 if (pfd=init_oscam_ser_device(oscam_ser_device))
884 oscam_ser_server();
885 else
886 sleep(60); // retry in 1 min. (USB-Device ?)
887 if (pfd) close(pfd);
888 }
889}
890
891void init_oscam_ser(int idx)
892{
893 char *p;
894 while( (p=strrchr(cfg->ser_device, 1)) )
895 {
896 *p=0;
897 oscam_ser_fork(idx, p+1);
898 }
899 oscam_ser_fork(idx, cfg->ser_device);
900}
901
902/*
903 * client functions
904 */
905
906static int oscam_ser_client_init()
907{
908 if ((!reader[ridx].device[0])) cs_exit(1);
909 if (!oscam_ser_parse_url(reader[ridx].device)) cs_exit(1);
910 pfd=init_oscam_ser_device(oscam_ser_device);
911 return((pfd>0) ? 0 : 1);
912}
913
914static int oscam_ser_send_ecm(ECM_REQUEST *er, uchar *buf)
915{
916 switch(oscam_ser_proto)
917 {
918 case P_HSIC:
919 memset(buf, 0, 12);
920 buf[0]=2;
921 memcpy(buf+ 1, i2b(2, er->caid ), 2);
922 memcpy(buf+ 3, i2b(3, er->prid ), 3);
923 memcpy(buf+ 6, i2b(2, er->pid ), 2);
924 memcpy(buf+10, i2b(2, er->srvid), 2);
925 memcpy(buf+12, er->ecm, er->l);
926 oscam_ser_send(buf, 12+er->l);
927 break;
928 case P_BOMBA:
929 oscam_ser_send(er->ecm, er->l);
930 break;
931 case P_DSR95:
932 if( dsr9500type==P_DSR_WITHSID )
933 {
934 sprintf((char *)buf, "%c%08lX%04X%s%04X\n\r",
935 3, er->prid, er->caid, cs_hexdump(0, er->ecm, er->l), er->srvid);
936 oscam_ser_send(buf, (er->l<<1)+19); // 1 + 8 + 4 + l*2 + 4 + 2
937 }
938 else
939 {
940 sprintf((char *)buf, "%c%08lX%04X%s\n\r",
941 3, er->prid, er->caid, cs_hexdump(0, er->ecm, er->l));
942 oscam_ser_send(buf, (er->l<<1)+15); // 1 + 8 + 4 + l*2 + 2
943 }
944 break;
945 case P_ALPHA:
946 buf[0]=0x80;
947 memcpy(buf+1, i2b(2, 2+er->l), 2);
948 memcpy(buf+3, i2b(2, er->caid), 2);
949 memcpy(buf+5, er->ecm, er->l);
950 oscam_ser_send(buf, oscam_ser_alpha_convert(buf, 5+er->l));
951 break;
952 }
953 return(0);
954}
955
956static void oscam_ser_process_dcw(uchar *dcw, int *rc, uchar *buf, int l)
957{
958 switch(oscam_ser_proto)
959 {
960 case P_HSIC:
961 if ((l>=23) && (buf[2]==0x3A) && (buf[3]==0x3A))
962 {
963 int i;
964 uchar crc;
965 for (i=4, crc=HSIC_CRC; i<20; i++)
966 crc^=buf[i];
967 if (crc==buf[20])
968 {
969 memcpy(dcw, buf+4, 16);
970 *rc=1;
971 }
972 }
973 break;
974 case P_BOMBA:
975 if (l>=16)
976 {
977 memcpy(dcw, buf, 16);
978 *rc=1;
979 }
980 break;
981 case P_DSR95:
982 if ((l>=17) && (buf[0]==4))
983 {
984 memcpy(dcw, buf+1, 16);
985 *rc=1;
986 }
987 break;
988 case P_ALPHA:
989 if ((l>=19) && (buf[0]==0x88))
990 {
991 memcpy(dcw, buf+3, 16);
992 *rc=1;
993 }
994 break;
995 }
996}
997
998static int oscam_ser_recv_chk(uchar *dcw, int *rc, uchar *buf, int n)
999{
1000 *rc=(-1);
1001 switch (buf[0]>>4)
1002 {
1003 case IS_DCW:
1004 oscam_ser_process_dcw(dcw, rc, buf+1, n-1);
1005 break;
1006 }
1007 return((*rc<0) ? (-1) : 0); // idx not supported in serial module
1008}
1009
1010/*
1011 * protocol structure
1012 */
1013
1014void module_oscam_ser(struct s_module *ph)
1015{
1016 strcpy(ph->desc, "serial");
1017 ph->type=MOD_CONN_SERIAL;
1018 ph->multi=1;
1019 ph->watchdog=0;
1020 ph->s_handler=init_oscam_ser;
1021 ph->recv=oscam_ser_recv;
1022 ph->send_dcw=oscam_ser_send_dcw;
1023 ph->c_multi=0;
1024 ph->c_init=oscam_ser_client_init;
1025 ph->c_recv_chk=oscam_ser_recv_chk;
1026 ph->c_send_ecm=oscam_ser_send_ecm;
1027}
Note: See TracBrowser for help on using the repository browser.