#!perl -w use strict; $|=1; my @intypes=qw(INDI RESP NOTI); my %intype; $intype{$_+1}=$intypes[$_] for 0..$#intypes; my @outtypes=qw(EXEC GET SET CFRM EVENT); my %outtype; $outtype{$_+1}=$outtypes[$_] for 0..$#outtypes; my %type=(0x00=>\%intype, 0xff=>\%outtype); my @msgclasses=qw(PWR CALL - SMS SEC PB DISP NET SND MISC SVC SS GPRS SAT CFG IMEI GPS SAP); my %msgclass; $msgclass{$_+1}=$msgclasses[$_] for 0..$#msgclasses; my @msgcodes=( [qw(PHONE_PWR_UP PHONE_PWR_OFF PHONE_RESET BATT_STATUS BATT_TYPE BATT_COMP PHONE_ONLINE)], [qw(OUTGOING INCOMING RELEASE ANSWER STATUS LIST BURST_DTMF CONT_DTMF WAITING LINE_ID)], [qw()], [qw(SEND_MSG INCOMING_MSG READ_MSG SAVE_MSG DEL_MSG DELIVER_REPORT DEVICE_READY SEL_MEM STORED_MSG_COUNT SVC_CENTER_ADDR SVC_OPTION MEM_STATUS CBS_MSG CBS_CONFIG STORED_MSG_STATUS PARAM_COUNT PARAM)], [qw(PIN_STATUS PHONE_LOCK CHANGE_LOCKING_PW SIM_LANG RSIM_ACCESS GSIM_ACCESS SIM_ICC_TYPE LOCK_INFOMATION IMS_AUTH)], [qw(ACCESS STORAGE STORAGE_LIST ENTRY_INFO CAPA)], [qw(ICON_INFO HOMEZONE_INFO)], [qw(PREF_PLMN PLMN_SEL CURRENT_PLMN PLMN_LIST REGIST SUBSCRIBER_NUM BAND_SEL SERVICE_DOMAIN_CONFIG POWERON_ATTACH MODE_SEL ACQ_ORDER IDENTITY)], [qw(KEY_TONE NOTI_TONE LED_CTRL VIB_CTRL SPKR_VOLUME_CTRL MIC_GAIN_CTRL MIC_MUTE_CTRL SPKR_PHONE_CTRL HFK_AUTIO_STARTSTOP VOICECALL_RECORD_REPORT AUDIO_PATH_CTRL AUDIO_SOURCE_CTRL USER_SND_CONFIG GAIN_CTRL QUIET_MODE_CTRL DYVE_MODE_CTRL)], [qw(ME_VERSION ME_IMSI ME_SN KEYCODE_REQUEST DIAG_KEYCODE CDMA_MDN TIME_INFO CDMA_FEATURE NETWORK_CHANGE VCALL_CHANNEL_ID PHONE_DEBUG UNKNOWN__ UNKNOWN__ DIAG_TOUCH_TEST)], [qw(ENTER END PRO_KEYCODE SCREEN_CFG DISPLAY_SCREEN CHANGE_SVC_MODE DEVICE_TEST)], [qw(WAITING CLI BARRING BARRING_PW FORWARDING INFO MANAGE_CALL USSD AOC RELEASE_COMPLETE)], [qw(DEFINE_PDP_CONTEXT QOS PS PDP_CONTEXT ENTER_DATA SHOW_PDP_ADDR MS_CLASS 3G_QUAL_SRVC_PROFILE IP_CONFIGURATION DEFINE_SEC_PDP_CONTEXT TFT HSDPA_STATUS UNKNOWN__ DATA_DORMANT DUN_PIN_CTRL CALL_STATUS)], [qw(PROFILE_DOWNLOAD ENVELOPE_CMD PROACTIVE_CMD TERMINATE_USAT_SESSION EVENT_DOWNLOAD PROVIDE_LOCAL_INFO POLLING REFRESH SETUP_EVENT_LIST CALL_CONTROL_RESULT IMAGE_CLUT SETUP_CALL_PROCESSING SIM_INITIATE_MESSAGE)], [qw(DEFAULT_CONFIG EXTERNAL_DEVICE MAC_ADDRESS CONFIGURATION_ITEM PDA_CALIBRATION BT_WIFI_TEST TTY HSDPA_TMP_SETTING HSDPA_PERM_SETTING FM_RADIO_TEST MP3_SDCARD_TEST AUDIO_LOOPBACK_TEST BT_TEST MEMORY_FORMAT_TEST RF_MAX_POWER_TEST)], [qw(START CHECK_DEVICE_INFO PRE_CONFIG WRITE_ITEM REBOOT VERIFY_FACTORY_RESET COMPARE_ITEM MASS_STORAGE_INFO)], [qw(OPEN CLOSE START DEVICE_STATE VERIFICATION OPTION TTFF DISPLAY_SUPLFLOW XTRA_SET_TIME_INFO XTRA_SET_DATA XTRA_CLIENT_INIT_DOWNLOAD XTRA_QUERY_DATA_VALIDITY XTRA_SET_AUTO_DOWNLOAD XTRA_SET_XTRA_ENABLE XTRA_DOWNLOAD XTRA_VALIDITY_STATUS XTRA_TIME_EVENT XTRA_DATA_INJECTION_STATUS AGPS_PDP_CONNECTION AGPS_DNS_QUERY AGPS_SSL AGPS_MODE)], [qw(CONNECT STATUS TRANSFER_ATR TRANSFER_APDU TRANSPORT_PROTOCOL SIM_POWER TRANSFER_CARD_READER_STATUS)], ); my %msgcode; sub ipccalltype { return "VOICE" if ($_[0]==1); return "DATA" if ($_[0]==2); return "VIDEO" if ($_[0]==3); return sprintf("calltype_%02x", $_[0]); } sub ipccallflag { return sprintf("callflag_%02x", $_[0]); } my %decoders=( "EXEC:CALL:OUTGOING"=>sub { my ($type,$flag, $addr)=unpack("CCv/a", $_[0]); return sprintf("%s %s \"%s\"", ipccalltype($type), ipccallflag($flag), $addr); }, "NOTI:CALL:INCOMING"=>sub { my ($type, $callid, $lineid)= unpack("CCC", $_[0]); return sprintf("%s call-%d line-%d", ipccalltype($type), $callid, $lineid); }, "IP"=>sub { my ($iphdr, undef, $proto, undef, $src, $dst, $ippayload)=unpack("Ca8Ca2a4a4a*", $_[0]); return if ($iphdr!=0x45); if ($proto==0x11) { my ($srcport, $dstport, $udplen, $udpchk, $payload)= unpack("nnnna*", $ippayload); return sprintf("UDP %s:%d->%s:%d %s", ipaddr($src), $srcport, ipaddr($dst), $dstport, datastr($payload)); } elsif ($proto==6) { my ($srcport, $dstport, $seqnr, $acknr, $hlenxx, $flags, $wsize, $tcpchk, $options, $payload)= unpack("nnNNCCnnna*", $ippayload); my $hlen= $hlenxx>>4; return sprintf("TCP %s:%d->%s:%d %s", ipaddr($src), $srcport, ipaddr($dst), $dstport, datastr($payload)); } else { return sprintf("%02x %s->%s %s", $proto, ipaddr($src), ipaddr($dst), datastr($ippayload)); } } ); sub ipaddr { return join ".", unpack 'C*', $_[0]; } for my $cls (0..$#msgcodes) { $msgcode{$cls+1}{$_+1}=$msgcodes[$cls][$_] for 0..$#{$msgcodes[$cls]}; } $msgcode{0x80}{1}="RESPONSE"; $msgclass{0x80}="GEN"; sub msgtype { if (!exists $type{$_[0]}) { return sprintf("UNK%02x_%02x", $_[0], $_[1]); } if (!exists $type{$_[0]}{$_[1]}) { return sprintf("UNK%02x_%02x", $_[0], $_[1]); } return $type{$_[0]}{$_[1]}; } sub msgclass { if (!exists $msgclass{$_[0]}) { return sprintf("UNK%02x", $_[0]); } return $msgclass{$_[0]}; } sub msgcode { if (!exists $msgcode{$_[0]}) { return sprintf("UNK%02x_%02x", $_[0], $_[1]); } if (!exists $msgcode{$_[0]}{$_[1]}) { return sprintf("UNK%02x_%02x", $_[0], $_[1]); } return $msgcode{$_[0]}{$_[1]}; } my %dattype= ( 1=>"VIDEO", 0x5=>"CSD", 0x6=>"GPS", 0xA=>"IP1", 0xB=>"IP2", 0xC=>"IP3" ); sub dattype { if (!exists $dattype{$_[0]}) { return sprintf("UNK%02x", $_[0]); } return $dattype{$_[0]}; } sub decoderpcmsg { my $msg= shift; $msg =~ s/\s+//g; my $pkt= pack 'H*', $msg; my ($l1, $seq1, $l2, $seq2, $dir, $msgclass, $msgcode, $msgtype, $data)= unpack("vCvCCCCCa*", $pkt); printf("WARN: ld=%d mismatch l1=%d\n", length($pkt), $l1) if (length($pkt)!=$l1); printf("WARN: l1=%d mismatch l2=%d\n", $l1, $l2) if ($l1-$l2!=3); my $tag= msgtype($dir, $msgtype).':'.msgclass($msgclass).':'.msgcode($msgclass, $msgcode); my $txt; if (exists $decoders{$tag}) { $txt= &{$decoders{$tag}}($data); } if (!defined $txt) { $txt= datastr($data); } printf("%02x:%02x:%02x %-8s %-5s %-4s %-30s %s\n", $seq1, $seq2, $dir, sprintf("%d.%d.%d", $msgclass, $msgcode, $msgtype), msgtype($dir, $msgtype), msgclass($msgclass), msgcode($msgclass, $msgcode), $txt); } sub decodedatmsg { my ($msg, $dir)= @_; $msg =~ s/\s+//g; my $pkt= pack 'H*', $msg; my ($l1, $type, $data)= unpack("vva*", $pkt); printf("WARN: ld=%d mismatch l1=%d\n", length($pkt), $l1) if (length($pkt)!=$l1); my $tag= dattype($type); my $txt; if (exists $decoders{$tag}) { $txt= &{$decoders{$tag}}($data); } if (!defined $txt) { $txt= datastr($data); } printf("%s%s %s\n", $tag, $dir, $txt); } sub datastr { my $data=shift; my $s=""; my $ppos=0; while ($data =~ /(?:[\x20-\x7e]\x00){3,}|[\x20-\x7e]{3,}/g) { my $match=$&; my $pos=pos($data)-length($match); $s .= sprintf(" %s", unpack("H*", substr($data, $ppos, $pos-$ppos))); if ($match =~ /\x00/) { $s .= sprintf(" L\"%s\"", pack 'C*', unpack 'v*', $match); } else { $s .= sprintf(" \"%s\"", $match); } $ppos= $pos+length($match); } $s .= sprintf(" %s", unpack("H*", substr($data, $ppos))); return $s; } while(<>) { if (/TIMESTAMP\S* (\S+ \S+) @(\w+)\(.*?\)\s\w+\s(\w+)\s\S+\s+:\s\w+\sbytes\s*:\s*(\w.*\w)/) { my ($ts, $msec, $type, $data)=($1,hex($2), $3, $4); if ($data !~ /^7f (.*) 7e$/) { printf("WARN: no start/end in msg: %s %s\n", $ts, $data); next; } $data= $1; for my $msg (split(/ 7e 7f /, $data)) { printf("TIMESTAMP: %s @%08lx ", $ts, $msec); if ($type =~ /1/) { decoderpcmsg($msg); } else { decodedatmsg($msg, $type =~ /rd/ ? "<" : ">"); } } } }