Files
pysim/pySim/ts_31_102_telecom.py
Harald Welte 13edf30d6c filesystem: Use Tuple for transparent file size
As the documentation strings say: The size should be a *tuple*.  In
reality we so far passed a set.  The problem with the set is that
ordering is not guaranteed, and hence we cannot assume the first and
second item have meaning (minimum vs. default size).

While at it, use a type annotation to catch such bugs easily.

Change-Id: I553616f8c6c4aaa8f635b3d7d94e8e8f49ed5a56
2022-07-21 22:48:59 +02:00

291 lines
11 KiB
Python

# -*- coding: utf-8 -*-
# without this, pylint will fail when inner classes are used
# within the 'nested' kwarg of our TlvMeta metaclass on python 3.7 :(
# pylint: disable=undefined-variable
"""
DF_PHONEBOOK, DF_MULTIMEDIA, DF_MCS as specified in 3GPP TS 31.102 V16.6.0
Needs to be a separate python module to avoid cyclic imports
"""
#
# Copyright (C) 2022 Harald Welte <laforge@osmocom.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from pySim.tlv import *
from pySim.filesystem import *
from pySim.construct import *
from construct import Optional as COptional
from construct import *
# TS 31.102 Section 4.2.8
class EF_UServiceTable(TransparentEF):
def __init__(self, fid, sfid, name, desc, size, table, **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, **kwargs)
self.table = table
@staticmethod
def _bit_byte_offset_for_service(service: int) -> Tuple[int, int]:
i = service - 1
byte_offset = i//8
bit_offset = (i % 8)
return (byte_offset, bit_offset)
def _decode_bin(self, in_bin):
ret = {}
for i in range(0, len(in_bin)):
byte = in_bin[i]
for bitno in range(0, 8):
service_nr = i * 8 + bitno + 1
ret[service_nr] = {
'activated': True if byte & (1 << bitno) else False
}
if service_nr in self.table:
ret[service_nr]['description'] = self.table[service_nr]
return ret
def _encode_bin(self, in_json):
# compute the required binary size
bin_len = 0
for srv in in_json.keys():
service_nr = int(srv)
(byte_offset, bit_offset) = EF_UServiceTable._bit_byte_offset_for_service(
service_nr)
if byte_offset >= bin_len:
bin_len = byte_offset+1
# encode the actual data
out = bytearray(b'\x00' * bin_len)
for srv in in_json.keys():
service_nr = int(srv)
(byte_offset, bit_offset) = EF_UServiceTable._bit_byte_offset_for_service(
service_nr)
if in_json[srv]['activated'] == True:
bit = 1
else:
bit = 0
out[byte_offset] |= (bit) << bit_offset
return out
def get_active_services(self, cmd):
# obtain list of currently active services
(service_data, sw) = cmd.lchan.read_binary_dec()
active_services = []
for s in service_data.keys():
if service_data[s]['activated']:
active_services.append(s)
return active_services
def ust_service_check(self, cmd):
"""Check consistency between services of this file and files present/activated"""
num_problems = 0
# obtain list of currently active services
active_services = self.get_active_services(cmd)
# iterate over all the service-constraints we know of
files_by_service = self.parent.files_by_service
try:
for s in sorted(files_by_service.keys()):
active_str = 'active' if s in active_services else 'inactive'
cmd.poutput("Checking service No %u (%s)" % (s, active_str))
for f in files_by_service[s]:
should_exist = f.should_exist_for_services(active_services)
try:
cmd.lchan.select_file(f)
sw = None
exists = True
except SwMatchError as e:
sw = str(e)
exists = False
if exists != should_exist:
num_problems += 1
if exists:
cmd.perror(" ERROR: File %s is selectable but should not!" % f)
else:
cmd.perror(" ERROR: File %s is not selectable (%s) but should!" % (f, sw))
finally:
# re-select the EF.UST
cmd.lchan.select_file(self)
return num_problems
# TS 31.102 Section 4.4.2.1
class EF_PBR(LinFixedEF):
def __init__(self, fid='4F30', name='EF.PBR', desc='Phone Book Reference', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
#self._tlv = FIXME
# TS 31.102 Section 4.4.2.12.2
class EF_PSC(TransparentEF):
_construct = Struct('synce_counter'/Int32ub)
def __init__(self, fid='4F22', name='EF.PSC', desc='Phone Book Synchronization Counter', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
#self._tlv = FIXME
# TS 31.102 Section 4.4.2.12.3
class EF_CC(TransparentEF):
_construct = Struct('change_counter'/Int16ub)
def __init__(self, fid='4F23', name='EF.CC', desc='Change Counter', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
# TS 31.102 Section 4.4.2.12.4
class EF_PUID(TransparentEF):
_construct = Struct('previous_uid'/Int16ub)
def __init__(self, fid='4F24', name='EF.PUID', desc='Previous Unique Identifer', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
# TS 31.102 Section 4.4.2
class DF_PHONEBOOK(CardDF):
def __init__(self, fid='5F3A', name='DF.PHONEBOOK', desc='Phonebook', **kwargs):
super().__init__(fid=fid, name=name, desc=desc, **kwargs)
files = [
EF_PBR(),
EF_PSC(),
EF_CC(),
EF_PUID(),
# FIXME: Those 4Fxx entries with unspecified FID...
]
self.add_files(files)
# TS 31.102 Section 4.6.3.1
class EF_MML(BerTlvEF):
def __init__(self, fid='4F47', name='EF.MML', desc='Multimedia Messages List', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
# TS 31.102 Section 4.6.3.2
class EF_MMDF(BerTlvEF):
def __init__(self, fid='4F48', name='EF.MMDF', desc='Multimedia Messages Data File', **kwargs):
super().__init__(fid, name=name, desc=desc, **kwargs)
class DF_MULTIMEDIA(CardDF):
def __init__(self, fid='5F3B', name='DF.MULTIMEDIA', desc='Multimedia', **kwargs):
super().__init__(fid=fid, name=name, desc=desc, **kwargs)
files = [
EF_MML(),
EF_MMDF(),
]
self.add_files(files)
# TS 31.102 Section 4.6.4.1
EF_MST_map = {
1: 'MCPTT UE configuration data',
2: 'MCPTT User profile data',
3: 'MCS Group configuration data',
4: 'MCPTT Service configuration data',
5: 'MCS UE initial configuration data',
6: 'MCData UE configuration data',
7: 'MCData user profile data',
8: 'MCData service configuration data',
9: 'MCVideo UE configuration data',
10: 'MCVideo user profile data',
11: 'MCVideo service configuration data',
}
# TS 31.102 Section 4.6.4.2
class EF_MCS_CONFIG(BerTlvEF):
class McpttUeConfigurationData(BER_TLV_IE, tag=0x80):
pass
class McpttUserProfileData(BER_TLV_IE, tag=0x81):
pass
class McsGroupConfigurationData(BER_TLV_IE, tag=0x82):
pass
class McpttServiceConfigurationData(BER_TLV_IE, tag=0x83):
pass
class McsUeInitialConfigurationData(BER_TLV_IE, tag=0x84):
pass
class McdataUeConfigurationData(BER_TLV_IE, tag=0x85):
pass
class McdataUserProfileData(BER_TLV_IE, tag=0x86):
pass
class McdataServiceConfigurationData(BER_TLV_IE, tag=0x87):
pass
class McvideoUeConfigurationData(BER_TLV_IE, tag=0x88):
pass
class McvideoUserProfileData(BER_TLV_IE, tag=0x89):
pass
class McvideoServiceConfigurationData(BER_TLV_IE, tag=0x8a):
pass
class McsConfigDataCollection(TLV_IE_Collection, nested=[McpttUeConfigurationData,
McpttUserProfileData, McsGroupConfigurationData,
McpttServiceConfigurationData, McsUeInitialConfigurationData,
McdataUeConfigurationData, McdataUserProfileData,
McdataServiceConfigurationData, McvideoUeConfigurationData,
McvideoUserProfileData, McvideoServiceConfigurationData]):
pass
def __init__(self, fid='4F02', sfid=0x02, name='EF.MCS_CONFIG', desc='MCS configuration data', **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, **kwargs)
self._tlv = EF_MCS_CONFIG.McsConfigDataCollection
# TS 31.102 Section 4.6.4.1
class EF_MST(EF_UServiceTable):
def __init__(self, fid='4F01', sfid=0x01, name='EF.MST', desc='MCS Service Table', size=(2,2),
table=EF_MST_map, **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, table=table)
class DF_MCS(CardDF):
def __init__(self, fid='5F3D', name='DF.MCS', desc='Mission Critical Services', **kwargs):
super().__init__(fid=fid, name=name, desc=desc, **kwargs)
files = [
EF_MST(),
EF_MCS_CONFIG(),
]
self.add_files(files)
# TS 31.102 Section 4.6.5.2
EF_VST_map = {
1: 'MCPTT UE configuration data',
2: 'MCPTT User profile data',
3: 'MCS Group configuration data',
4: 'MCPTT Service configuration data',
5: 'MCS UE initial configuration data',
6: 'MCData UE configuration data',
7: 'MCData user profile data',
8: 'MCData service configuration data',
9: 'MCVideo UE configuration data',
10: 'MCVideo user profile data',
11: 'MCVideo service configuration data',
}
# TS 31.102 Section 4.6.5.2
class EF_VST(EF_UServiceTable):
def __init__(self, fid='4F01', sfid=0x01, name='EF.VST', desc='V2X Service Table', size=(2,2),
table=EF_VST_map, **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, table=table)
# TS 31.102 Section 4.6.5.3
class EF_V2X_CONFIG(BerTlvEF):
class V2xConfigurationData(BER_TLV_IE, tag=0x80):
pass
class V2xConfigDataCollection(TLV_IE_Collection, nested=[V2xConfigurationData]):
pass
def __init__(self, fid='4F02', sfid=0x02, name='EF.V2X_CONFIG', desc='V2X configuration data', **kwargs):
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, **kwargs)
self._tlv = EF_V2X_CONFIG.V2xConfigDataCollection
# TS 31.102 Section 4.6.5
class DF_V2X(CardDF):
def __init__(self, fid='5F3E', name='DF.V2X', desc='Vehicle to X', **kwargs):
super().__init__(fid=fid, name=name, desc=desc, **kwargs)
files = [
EF_VST(),
EF_V2X_CONFIG(),
]
self.add_files(files)