Introduction
Recently I in my work I had to encode an Inap (to be more precise – Sinap) content “by hand”. It’s not a rocket science however when you need to repeat this action several times it’s worth to prepare an “automatic” solution.
Input data
As an imput I have description of Furnish Charging Information in ASN.1:
FurnishChargingInformation ::= OPERATION ARGUMENT FurnishChargingInformationArg ERRORS {MissingParameter , TaskRefused , UnexpectedComponentSequence , UnexpectedDataValue , UnexpectedParameter }
FurnishChargingInformationArg ::= FCIBillingChargingCharacteristics
FCIBillingChargingCharacteristics ::= OCTET STRING (SIZE (minFCIBillingChargingLen..maxFCIBillingChargingLen))
Ok, how to read it? (S)INAP message FurnishChargingInformation has an argument FurnishChargingInformationArg which is eqal to FCIBillingChargingCharacteristics. FCIBillingChargingCharacteristics is a limited size octet string.
From Sinap description document I’ve found that FCIBillingChargingCharacteristics == FCIBCC.
Now it’s time to build FCIBCC module:
-- Creator: ASN.1 Editor (http://asneditor.sourceforge.net) -- Author: jhartman -- Created: Sun Apr 19 21:47:18 CEST 2009 FCI-Module DEFINITIONS IMPLICIT TAGS ::= BEGIN FCIBCC ::= SEQUENCE { chargedPartyID [0] ChargedPartyID , chargingInformation [1] ChargingInformation , chargedPartyType [2] ChargedPartyType OPTIONAL , legID [3] LegID OPTIONAL } ChargedPartyID ::= OCTET STRING (SIZE(minChargedPartyIDLen.. maxChargedPartyIDLen)) ChargingInformation ::= CHOICE { initChargingInformation [0] InitChargingInformation , updateChargingInformation [1] UpdateChargingInformation } InitChargingInformation ::= SEQUENCE { ticketControlInformation [0] TicketControlInformation OPTIONAL , callTypeAndStatus [1] CallTypeAndStatus OPTIONAL , billedItemList [2] BilledItemList OPTIONAL, inServiceSpecificData [3] INServiceSpecificData OPTIONAL, transparentData [4] TransparentDataFCI OPTIONAL , serviceIndicator [5] ServiceIndicator OPTIONAL , chargingLevel [6] ChargingLevelControl OPTIONAL , zoningInPostProcessing [7] ZoningInformation OPTIONAL , takeOverChargingInformation [8] BOOLEAN OPTIONAL } INServiceSpecificData ::= OCTET STRING(SIZE(1 .. 199)) TicketControlInformation ::= SEQUENCE { sequenceInfo [0] SequenceInfoFCI DEFAULT firstFCI, ticketGenerationCondition [1] TicketGenerationCondition OPTIONAL } SequenceInfoFCI ::= ENUMERATED { firstFCI (0) , subsequentFCI (1) } TicketGenerationCondition ::= ENUMERATED { successfulAndUnsuccessfulCalls (0) , onlySuccessfulCalls (1) , onlyUnsuccessfulCalls (2) } CallTypeAndStatus ::= INTEGER (0..999) BilledItemList ::= SEQUENCE SIZE(minBilledItemNum..maxBilledItemNum) OF BilledItem BilledItem ::= OCTET STRING (SIZE(minBilledItemLen..maxBilledItemLen)) TransparentDataFCI ::= OCTET STRING (SIZE(minTransparentDataFCILen..maxTransparentDataFCILen)) ServiceIndicator ::= Integer2 ChargingLevelControl ::= CHOICE { scpChargeNumber [0] ScpChargeNumber , zoningRequired [1] SSPZoningInformation , freeOfCharge [2] NULL } ScpChargeNumber ::= OCTET STRING (SIZE(fixScpChargeNumberLen)) SSPZoningInformation ::= CHOICE { lacAParty-BParty [0] NULL , lacAParty-lacSSP [1] NULL , lacAParty-DDigits [2] DDigits } ZoningInformation ::= CHOICE { lacAParty-BParty [0] NULL , lacAParty-lacSSP [1] NULL , lacAParty-Ddigits [2] DDigits , lacSSP-BParty [3] NULL , oDigits-Bparty [4] ODigits } DDigits ::= GenericDigits ODigits ::= GenericDigits -- UpdateChargingInformation UpdateChargingInformation ::= SEQUENCE { newChargedPartyType [0] ChargedPartyType OPTIONAL , newChargedPartyID [1] ChargedPartyID OPTIONAL , addBilledItemList [2] BilledItemList OPTIONAL } ChargedPartyType ::= OCTET STRING (SIZE(fixChargedPartyTypeLen)) LegID ::= CHOICE { sendingSideID [0] LegType -- used in operations sent from SCF to SSF -- , receivingSideID [1] LegType -- used in operations sent from SSF to SCF -- } LegType ::= OCTET STRING (SIZE (fixLegTypeLen)) Integer2 ::= INTEGER (0..65535) GenericDigits ::= OCTET STRING (SIZE (minGenericDigitsLen..maxGenericDigitsLen)) -- constrains minBilledItemLen INTEGER ::= 1 maxBilledItemLen INTEGER ::= 3 minBilledItemNum INTEGER ::= 1 maxBilledItemNum INTEGER ::= 3 minChargedPartyIDLen INTEGER ::= 1 maxChargedPartyIDLen INTEGER ::= 16 fixChargedPartyTypeLen INTEGER ::= 1 minTransparentDataFCILen INTEGER ::= 1 maxTransparentDataFCILen INTEGER ::= 20 fixLegTypeLen INTEGER ::= 1 minGenericDigitsLen INTEGER ::= 1 maxGenericDigitsLen INTEGER ::= 26 fixScpChargeNumberLen INTEGER ::= 2 END
(save whole module as FCI-Module.asn)
What’s this? It’s a top-down definition of all elements needed to describe FCIBCC.
Building the tool
We have prepared an abstract description of FCIBCC. “Abstract” means – has no mapping to real bits and bytes yet. However, we know that in INAP protocol bytes are encoded according to BER notation. Let’s take a pen, piece of paper and spend some time to create hex output we’re looking for. Wait, this is not the way we would like to go. We’re looking for a tool 🙂
First – let’s get an ASN.1 compiler. Usually, commercial tool costs a lot of $$$. Really LOT. Lucky – I’ve found one freeware. Look for open source ANS.1 compiler. Download it and build on your platform.
Next, compile FCI-Module.asn. It should compile without errors:
Jarek-Hartmans-Mac:asn1-2 jhartman$ asn1c FCI-Module.asn Compiled FCIBCC.c (contents unchanged) Compiled FCIBCC.h (contents unchanged) Compiled ChargedPartyID.c (contents unchanged) Compiled ChargedPartyID.h (contents unchanged) Compiled ChargingInformation.c (contents unchanged) Compiled ChargingInformation.h (contents unchanged) Compiled InitChargingInformation.c (contents unchanged) Compiled InitChargingInformation.h (contents unchanged) Compiled INServiceSpecificData.c (contents unchanged) Compiled INServiceSpecificData.h (contents unchanged) Compiled TicketControlInformation.c (contents unchanged) Compiled TicketControlInformation.h (contents unchanged) Compiled SequenceInfoFCI.c (contents unchanged) Compiled SequenceInfoFCI.h (contents unchanged) Compiled TicketGenerationCondition.c (contents unchanged) Compiled TicketGenerationCondition.h (contents unchanged) Compiled CallTypeAndStatus.c (contents unchanged)
.
.
.
An output we got a source file for our tool. Now it’s time to build the tool:
Jarek-Hartmans-Mac:asn1-2 jhartman$ cc -DPDU=FCIBCC -I. *.c -o FCI converter-sample.c: In function 'add_bytes_to_buffer': converter-sample.c:485: warning: pointer targets in assignment differ in signedness converter-sample.c: In function 'data_decode_from_file': converter-sample.c:539: warning: pointer targets in assignment differ in signedness converter-sample.c:577: warning: pointer targets in assignment differ in signedness converter-sample.c:580: warning: pointer targets in assignment differ in signedness
(we got several warnings but just ignore them)
Success!
Using the tool
Our goal is to prepare flow of hex numbers that’s corresponding to following XER data:
<FCIBCC> <chargedPartyID>21 43</chargedPartyID> <chargingInformation> <initChargingInformation> <ticketControlInformation> <sequenceInfo><subsequentFCI/></sequenceInfo> <ticketGenerationCondition><onlySuccessfulCalls/></ticketGenerationCondition> </ticketControlInformation> </initChargingInformation> </chargingInformation> <legID> <sendingSideID>01</sendingSideID> </legID> </FCIBCC>
(save it as FCI.xer)
If you compare XER data with FCI-Module.asn you can easily recognise what’s going on. XER encoding is very handy human-readable format for all this ASN.1 stuff. Let’s convert it to real BER (to be more precise – DER):
Jarek-Hartmans-Mac:asn1-2 jhartman$ ./FCI -ixer -oder FCI-TP-FPH.xer | hexdump 0000000 30 26 80 09 54 65 73 74 5f 65 77 73 64 a1 19 a0 0000010 17 a0 03 80 01 00 81 02 03 e7 a2 05 04 03 01 00 0000020 00 84 02 80 00 85 01 01
When you copy these hex numbers into your IN application and put FCI message on the wire you should get something similar to:
Can you recognize highlighted numbers? Yes, yes – they are exactly the same as we got from our FCI-converter.
Let’s assume now we would like to convert hex (or more precise – BER encoded) FurnishChargingInformationArg to human readable XML.
Save highlighted element. In Wireshark I’m using right mouse button -> Copy -> Hex (Hex stream). Save it to txt file:
Jarek-Hartmans-Mac:asn1-2 jhartman$ cat FCI-from-wireshark.txt 301580022143a10aa008a006800101810101a303800101
Now convert hex-text file into real binary:
Jarek-Hartmans-Mac:asn1-2 jhartman$ xxd -r -p FCI-from-wireshark.txt > FCI-from-wireshark.ber
Now we can convert BER stream into human-readable format using our hand-made tool:
Jarek-Hartmans-Mac:asn1-2 jhartman$ ./FCI FCI-from-wireshark.ber <FCIBCC> <chargedPartyID>21 43</chargedPartyID> <chargingInformation> <initChargingInformation> <ticketControlInformation> <sequenceInfo><subsequentFCI/></sequenceInfo> <ticketGenerationCondition><onlySuccessfulCalls/></ticketGenerationCondition> </ticketControlInformation> </initChargingInformation> </chargingInformation> <legID> <sendingSideID>01</sendingSideID> </legID> </FCIBCC>
Pretty cool, heh?
References
- ASN.1 introduction with links to ITU-T references
- Wonderfull introduction to ASN.1: “A Layman’s Guide to a Subset of ASN.1, BER, and DER”. Read it if you need more informations.
- Great books: “ASN.1 – Communication Between Heterogeneous Systems” and “ASN.1 Complete”. If you need more in-deep details.
- Freeware ASN.1 compiler: ANS.1 compiler.