/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.io.*;
import java.util.*;
import java.text.*;

public class DmxApi {
 public static class DSCConfig {
  int id;
  int pid;
  String alg;

  public DSCConfig(int id,int pid,String alg) {
   this.id=id;
   this.pid=pid;
   this.alg=alg;
  }
 }

 public static final String DEMUX0_DESCRAMBLERS   = "/proc/driver/demux/demux0/descramblers";
 public static final int BUFSIZE                  = 25*256;

 public static final int INVALID_PID              = 0x2000;

 public static final int DVB_DEMUX_SOURCE_FRONT0  = 0;
 public static final int DVB_DEMUX_SOURCE_FRONT1  = 1;
 public static final int DVB_DEMUX_SOURCE_DVR0    = 2;

 public static final int FLG_DONT_UPDATE_READ_PTR = 1;
 public static final int FLG_DONT_INVALIDATE_MEM  = 2;

 public static final int MAP_SHARED  = 0x01;
 public static final int MAP_PRIVATE = 0x02;

 public static final int PROT_READ   = 0x01;
 public static final int PROT_WRITE  = 0x02;

 private static NativeCode nc;

 static {
  nc=NativeCode.getInstance();
 }

 static String[] str2tokens(String s) {
  s=s.trim();

  StringTokenizer st=new StringTokenizer(s," ", false);
  int cnt=st.countTokens();

  String tokens[]=new String[cnt];

  for(int i=0;i<cnt;i++) {
   tokens[i]=st.nextToken();
  }            

  return tokens;
 }

 private static Vector read_dsc_config() {
  Vector res=new Vector();

  try {
   byte data[]=FS.sys_get_proc_file(DEMUX0_DESCRAMBLERS);

   ByteArrayInputStream in=new ByteArrayInputStream(data);
   BufferedReader b=new BufferedReader(new InputStreamReader(in,"utf-8"));

   String line=b.readLine();

   //header line
   line=b.readLine();

   while(line!=null) {
    String tokens[]=str2tokens(line);

    int id=Integer.parseInt(tokens[0]);
    int pid=Integer.parseInt(tokens[2].substring(2),16);
    String alg=tokens[3];

    DSCConfig dsccfg=new DSCConfig(id,pid,alg);
    res.add(dsccfg);

    line=b.readLine();
   }
    
   b.close();
   in.close();
  } catch(Throwable t) {}

  return res;
 }

 public static void setup_descrambler(int fd) {
  Vector des=read_dsc_config();

  for(int i=0;i<des.size();i++) {
   DSCConfig dsc=(DSCConfig)des.elementAt(i);

   if (dsc.pid!=INVALID_PID) {
    int res=dmx_dsc_SetPid(fd,dsc.id,dsc.pid,0);
    ApiMonitor.log("dmx_dsc_SetPid id "+dsc.id+" pid "+Utils.hex_value(dsc.pid,9)+" res "+res);
   }
  }
 }

 public static final int dmx_open(int type) {
  int id=-1;

  switch(SysInfo.hwid) {
   case SysInfoDefs.ITI5800S:
    switch(type) {
     case DVB_DEMUX_SOURCE_FRONT0:
      id=0;
      break;
     case DVB_DEMUX_SOURCE_DVR0:
      id=1;
      break;
    }    
    break;

   case SysInfoDefs.ITI5800SX:
    switch(type) {
     case DVB_DEMUX_SOURCE_FRONT0:
      id=1;
      break;
     case DVB_DEMUX_SOURCE_FRONT1:
      id=0;
      break;
     case DVB_DEMUX_SOURCE_DVR0:
      id=2;
      break;
    }    
    break;

   case SysInfoDefs.ITI2850ST:
   case SysInfoDefs.ITI2851S:
    switch(type) {
     case DVB_DEMUX_SOURCE_FRONT0:
      id=1;
      break;
     case DVB_DEMUX_SOURCE_FRONT1:
      id=0;
      break;
     case DVB_DEMUX_SOURCE_DVR0:
      id=2;
      break;
    }    
    break;
  }

  if (id<0) return id;

  int fd=Syscall.open("/dev/dmx"+id,FSDefs.O_RDONLY);

  return fd;
 }

 public static void dmx_close(int fd) {
  Syscall.close(fd);
 }

 public static int dmx_channel_GetHwBufferInfo(int fd,int buf) {
  Utils.memset(buf,0,0x10);

  int res=Syscall.ioctl(fd,0x8010442e,buf);

  return res;
 }

 public static int dmx_channel_Start(int fd) {
  int res=Syscall.ioctl(fd,0x00004429,0);

  return res;
 }

 public static int dmx_channel_Stop(int fd) {
  int res=Syscall.ioctl(fd,0x0000442a,0);

  return res;
 }

 public static int dmx_channel_ts_PidAdd(int fd,int pid) {
  int buf=nc.malloc(0x02);

  Memory.write_byte(buf,pid&0xff);
  Memory.write_byte(buf+1,(pid>>8)&0xff);

  int res=Syscall.ioctl(fd,0x4002442b,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_channel_ts_PidClear(int fd,int pid) {
  int buf=nc.malloc(0x02);

  Memory.write_byte(buf,pid&0xff);
  Memory.write_byte(buf+1,(pid>>8)&0xff);

  int res=Syscall.ioctl(fd,0x4002442c,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_channel_ts_SetFilter(int fd,int bufsize) {
  int buf=nc.malloc(0x20);
  Utils.memset(buf,0,0x20);

  Memory.write_dword(buf+0x04,bufsize);
  Memory.write_dword(buf+0x08,bufsize);

  Memory.write_dword(buf+0x10,0x00017800);

  Memory.write_dword(buf+0x14,0xffffffff);
  Memory.write_dword(buf+0x18,0x00000001);

  Memory.write_dword(buf+0x1c,FLG_DONT_INVALIDATE_MEM);

  int res=Syscall.ioctl(fd,0xC0204428,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_channel_ts_StartReinject(int fd) {
  int res=Syscall.ioctl(fd,0x4430,0);

  return res;
 }

 public static int dmx_channel_ts_StopReinject(int fd) {
  int res=Syscall.ioctl(fd,0x4431,0);

  return res;
 }

 public static int dmx_channel_ts_Collect(int fd,int buf) {
  int res=Syscall.ioctl(fd,0x800c442d,buf);

  return res;
 }

 public static int dmx_channel_ts_Ack(int fd,int size) {
  int buf=nc.malloc(0x04);
  Memory.write_dword(buf,size);

  int res=Syscall.ioctl(fd,0x8004443A,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_channel_ts_SetNotifyParams(int fd,int param1,int param2) {
  int buf=nc.malloc(0x08);
  Memory.write_dword(buf,param1);
  Memory.write_dword(buf+4,param2);

  int res=Syscall.ioctl(fd,0xC008443B,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_channel_ts_Mmap(int fd,int addr,int size) {
  return Syscall.mmap(addr,size,PROT_READ,MAP_PRIVATE,fd,0);
 }

 public static int dmx_channel_ts_Munmap(int fd,int addr,int size) {
  return Syscall.munmap(addr,size);
 }

 public static int dmx_channel_SetFilter_01(int fd,int pid) {
  int buf=nc.malloc(0x18);
  Utils.memset(buf,0,0x18);
  
  Memory.write_byte(buf,pid&0xff);
  Memory.write_byte(buf+1,(pid>>8)&0xff);

  Memory.write_dword(buf+0x04,0x40);  //source -> memory
  Memory.write_dword(buf+0x08,0x01);  //decoder id
  Memory.write_dword(buf+0x0c,0x00);  //PES filter (if == 1 then PCR filter)

  Memory.write_dword(buf+0x10,0x00060000);
  Memory.write_dword(buf+0x14,0x00002000);

  int res=Syscall.ioctl(fd,0x40184427,buf);

  nc.free(buf);

  return res;
 }


 public static int dmx_channel_FilterControl(int fd,int arg) {
  int buf=nc.malloc(0x02);

  Memory.write_byte(buf,0);
  Memory.write_byte(buf+1,arg);

  int res=Syscall.ioctl(fd,0x40024437,buf);

  nc.free(buf);

  return res;
 }

 public static int dmx_dsc_SetPid(int fd,int dsc_id,int pid,int dsc_type) {
  int buf=nc.malloc(0x10);

  Memory.write_dword(buf,dsc_id);
  Memory.write_dword(buf+4,0);
  Memory.write_word(buf+8,pid);
  Memory.write_word(buf+10,0);
  Memory.write_dword(buf+12,dsc_type);

  int res=Syscall.ioctl(fd,0x40104423,buf);

  nc.free(buf);

  return res;
 }
}
