diff --git a/pySim-prog.py b/pySim-prog.py index 0abd190b..4c85be70 100755 --- a/pySim-prog.py +++ b/pySim-prog.py @@ -146,7 +146,7 @@ def parse_options(): parser.add_option("--opmode", dest="opmode", type="choice", help="Set UE Operation Mode in EF.AD (Administrative Data)", default=None, - choices=['{:02X}'.format(m) for m in list(EF_AD.OP_MODE.keys())], + choices=['{:02X}'.format(int(m)) for m in EF_AD.OP_MODE], ) parser.add_option("--epdgid", dest="epdgid", help="Set Home Evolved Packet Data Gateway (ePDG) Identifier. (Only FQDN format supported)", diff --git a/pySim-read.py b/pySim-read.py index 59c57621..8e4a512d 100755 --- a/pySim-read.py +++ b/pySim-read.py @@ -28,7 +28,7 @@ import random import re import sys -from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD_mode_map +from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map @@ -230,11 +230,10 @@ def parse_options(): (res, sw) = card.read_binary('AD') if sw == '9000': print("Administrative data: %s" % (res,)) - if res[:2] in EF_AD_mode_map: - print("\tMS operation mode: %s" % (EF_AD_mode_map[res[:2]],)) - else: - print("\tMS operation mode: (unknown 0x%s)" % (res[:2],)) - if int(res[4:6], 16) & 0x01: + ad = EF_AD() + decoded_data = ad.decode_hex(res) + print("\tMS operation mode: %s" % decoded_data['ms_operation_mode']) + if decoded_data['ofm']: print("\tCiphering Indicator: enabled") else: print("\tCiphering Indicator: disabled") diff --git a/pySim-shell.py b/pySim-shell.py index 2a7c3777..a8db2635 100755 --- a/pySim-shell.py +++ b/pySim-shell.py @@ -30,7 +30,7 @@ import sys from pathlib import Path -from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD_mode_map +from pySim.ts_51_011 import EF, DF, EF_SST_map from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map diff --git a/pySim/cards.py b/pySim/cards.py index 5a39bda5..9a19eeda 100644 --- a/pySim/cards.py +++ b/pySim/cards.py @@ -175,29 +175,27 @@ def update_ad(self, mnc=None, opmode=None, ofm=None): # read from card raw_hex_data, sw = self._scc.read_binary(EF['AD'], length=None, offset=0) - raw_bin_data = h2b(raw_hex_data) - abstract_data = ad.decode_bin(raw_bin_data) + abstract_data = ad.decode_hex(raw_hex_data) # perform updates - if mnc: + if mnc and abstract_data['extensions']: mnclen = len(str(mnc)) if mnclen == 1: mnclen = 2 if mnclen > 3: raise RuntimeError('invalid length of mnc "{}"'.format(mnc)) - abstract_data['len_of_mnc_in_imsi'] = mnclen + abstract_data['extensions']['mnc_len'] = mnclen if opmode: - opmode_symb = ad.OP_MODE.get(int(opmode, 16)) - if opmode_symb: - abstract_data['ms_operation_mode'] = opmode_symb + opmode_num = int(opmode, 16) + if opmode_num in [int(v) for v in EF_AD.OP_MODE]: + abstract_data['ms_operation_mode'] = opmode_num else: raise RuntimeError('invalid opmode "{}"'.format(opmode)) if ofm: - abstract_data['specific_facilities']['ofm'] = bool(int(ofm, 16)) + abstract_data['ofm'] = bool(int(ofm, 16)) # write to card - raw_bin_data = ad.encode_bin(abstract_data) - raw_hex_data = b2h(raw_bin_data) + raw_hex_data = ad.encode_hex(abstract_data) data, sw = self._scc.update_binary(EF['AD'], raw_hex_data) return sw diff --git a/pySim/construct.py b/pySim/construct.py index 839497c7..b0f03b7e 100644 --- a/pySim/construct.py +++ b/pySim/construct.py @@ -47,3 +47,44 @@ def filter_dict(d, exclude_prefix='_'): # here we collect some shared / common definitions of data types LV = Prefixed(Int8ub, HexAdapter(GreedyBytes)) + +# Default value for Reserved for Future Use (RFU) bits/bytes +# See TS 31.101 Sec. "3.4 Coding Conventions" +__RFU_VALUE = 0 + +# Field that packs Reserved for Future Use (RFU) bit +FlagRFU = Default(Flag, __RFU_VALUE) + +# Field that packs Reserved for Future Use (RFU) byte +ByteRFU = Default(Byte, __RFU_VALUE) + +# Field that packs all remaining Reserved for Future Use (RFU) bytes +GreedyBytesRFU = Default(GreedyBytes, b'') + +def BitsRFU(n=1): + ''' + Field that packs Reserved for Future Use (RFU) bit(s) + as defined in TS 31.101 Sec. "3.4 Coding Conventions" + + Use this for (currently) unused/reserved bits whose contents + should be initialized automatically but should not be cleared + in the future or when restoring read data (unlike padding). + + Parameters: + n (Integer): Number of bits (default: 1) + ''' + return Default(BitsInteger(n), __RFU_VALUE) + +def BytesRFU(n=1): + ''' + Field that packs Reserved for Future Use (RFU) byte(s) + as defined in TS 31.101 Sec. "3.4 Coding Conventions" + + Use this for (currently) unused/reserved bytes whose contents + should be initialized automatically but should not be cleared + in the future or when restoring read data (unlike padding). + + Parameters: + n (Integer): Number of bytes (default: 1) + ''' + return Default(Bytes(n), __RFU_VALUE) diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py index c21e86c0..48649cd9 100644 --- a/pySim/ts_51_011.py +++ b/pySim/ts_51_011.py @@ -319,22 +319,12 @@ 59: 'MMS User Connectivity Parameters', } -# 10.3.18 "EF.AD (Administrative data) " -EF_AD_mode_map = { - '00' : 'normal operation', - '80' : 'type approval operations', - '01' : 'normal operation + specific facilities', - '81' : 'type approval operations + specific facilities', - '02' : 'maintenance (off line)', - '04' : 'cell test operation', -} - - from pySim.utils import * from struct import pack, unpack from construct import * from construct import Optional as COptional -from pySim.construct import HexAdapter, BcdAdapter +from pySim.construct import HexAdapter, BcdAdapter, FlagRFU, ByteRFU, GreedyBytesRFU, BitsRFU, BytesRFU +import enum from pySim.filesystem import * import pySim.ts_102_221 @@ -553,30 +543,34 @@ def __init__(self, fid='6f7e', sfid=None, name='EF.LOCI', desc='Location Informa # TS 51.011 Section 10.3.18 class EF_AD(TransparentEF): - OP_MODE = { - 0x00: 'normal', - 0x80: 'type_approval', - 0x01: 'normal_and_specific_facilities', - 0x81: 'type_approval_and_specific_facilities', - 0x02: 'maintenance_off_line', - 0x04: 'cell_test', - } - OP_MODE_reverse = dict(map(reversed, OP_MODE.items())) + class OP_MODE(enum.IntEnum): + normal = 0x00 + type_approval = 0x80 + normal_and_specific_facilities = 0x01 + type_approval_and_specific_facilities = 0x81 + maintenance_off_line = 0x02 + cell_test = 0x04 + #OP_MODE_DICT = {int(v) : str(v) for v in EF_AD.OP_MODE} + #OP_MODE_DICT_REVERSED = {str(v) : int(v) for v in EF_AD.OP_MODE} + def __init__(self, fid='6fad', sfid=None, name='EF.AD', desc='Administrative Data', size={3,4}): super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size) - def _decode_bin(self, raw_bin): - u = unpack('!BH', raw_bin[:3]) - ofm = True if u[1] & 1 else False - res = {'ms_operation_mode': self.OP_MODE.get(u[0], u[0]), 'specific_facilities': { 'ofm': ofm } } - if len(raw_bin) > 3: - res['len_of_mnc_in_imsi'] = int(raw_bin[3]) & 0xf - return res - def _encode_bin(self, abstract): - op_mode = self.OP_MODE_reverse[abstract['ms_operation_mode']] - res = pack('!BH', op_mode, abstract['specific_facilities']['ofm']) - if 'len_of_mnc_in_imsi' in abstract: - res += pack('!B', abstract['len_of_mnc_in_imsi']) - return res + self._construct = BitStruct( + # Byte 1 + 'ms_operation_mode'/Bytewise(Enum(Byte, EF_AD.OP_MODE)), + # Byte 2 + 'rfu1'/Bytewise(ByteRFU), + # Byte 3 + 'rfu2'/BitsRFU(7), + 'ofm'/Flag, + # Byte 4 (optional), + 'extensions'/COptional(Struct( + 'rfu3'/BitsRFU(4), + 'mnc_len'/BitsInteger(4), + # Byte 5..N-4 (optional, RFU) + 'extensions'/Bytewise(GreedyBytesRFU) + )) + ) # TS 51.011 Section 10.3.20 / 10.3.22 class EF_VGCS(TransRecEF): diff --git a/pysim-testdata/Fairwaves-SIM.ok b/pysim-testdata/Fairwaves-SIM.ok index e6fcfe30..f83f415e 100644 --- a/pysim-testdata/Fairwaves-SIM.ok +++ b/pysim-testdata/Fairwaves-SIM.ok @@ -43,7 +43,7 @@ HPLMNAcT: ACC: 0008 MSISDN: Not available Administrative data: 00000002 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: disabled SIM Service Table: ff3cc3ff030fff0f000fff03f0c0 Service 1 - CHV1 disable function diff --git a/pysim-testdata/Wavemobile-SIM.ok b/pysim-testdata/Wavemobile-SIM.ok index 1c78cc9f..0682a706 100644 --- a/pysim-testdata/Wavemobile-SIM.ok +++ b/pysim-testdata/Wavemobile-SIM.ok @@ -50,7 +50,7 @@ HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 6a82. ACC: abce MSISDN: Not available Administrative data: 00000102 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: enabled SIM Service Table: ff33ff0f3c00ff0f000cf0c0f0030000 Service 1 - CHV1 disable function diff --git a/pysim-testdata/fakemagicsim.ok b/pysim-testdata/fakemagicsim.ok index 1d1714fd..11296f5a 100644 --- a/pysim-testdata/fakemagicsim.ok +++ b/pysim-testdata/fakemagicsim.ok @@ -17,7 +17,7 @@ HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404. ACC: ffff MSISDN: Not available Administrative data: 000000 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: disabled SIM Service Table: ff3fff0f0300f003000c Service 1 - CHV1 disable function diff --git a/pysim-testdata/sysmoISIM-SJA2.ok b/pysim-testdata/sysmoISIM-SJA2.ok index ae332a8c..dc7b8657 100644 --- a/pysim-testdata/sysmoISIM-SJA2.ok +++ b/pysim-testdata/sysmoISIM-SJA2.ok @@ -55,7 +55,7 @@ HPLMNAcT: ACC: 0200 MSISDN (NPI=1 ToN=3): 6766266 Administrative data: 00000002 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: disabled SIM Service Table: ff33ffff3f003f0f300cf0c3f00000 Service 1 - CHV1 disable function diff --git a/pysim-testdata/sysmoUSIM-SJS1.ok b/pysim-testdata/sysmoUSIM-SJS1.ok index 95f6967a..bce3c9d9 100644 --- a/pysim-testdata/sysmoUSIM-SJS1.ok +++ b/pysim-testdata/sysmoUSIM-SJS1.ok @@ -55,7 +55,7 @@ HPLMNAcT: ACC: 0008 MSISDN (NPI=1 ToN=1): +77776336143 Administrative data: 00000002 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: disabled SIM Service Table: ff3fffff3f003f1ff00c00c0f00000 Service 1 - CHV1 disable function diff --git a/pysim-testdata/sysmosim-gr1.ok b/pysim-testdata/sysmosim-gr1.ok index f4b09c88..3aff2a39 100644 --- a/pysim-testdata/sysmosim-gr1.ok +++ b/pysim-testdata/sysmosim-gr1.ok @@ -17,7 +17,7 @@ HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404. ACC: 0008 MSISDN: Not available Administrative data: 000000 - MS operation mode: normal operation + MS operation mode: normal Ciphering Indicator: disabled SIM Service Table: ff3fff0f0f0000030000 Service 1 - CHV1 disable function