blob: 1b6b5d12dbcc2cbdf54c5aaf83c999fd918d34cc [file] [log] [blame]
Harald Weltef8d2e2b2023-07-09 17:58:38 +02001# -*- coding: utf-8 -*-
2
3""" pySim: various utilities only used by legacy tools (pySim-{prog,read})
4"""
5
6# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
7# Copyright (C) 2021 Harald Welte <laforge@osmocom.org>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21#
22
23from pySim.utils import Hexstr, rpad, enc_plmn
24from pySim.utils import dec_xplmn_w_act, dec_xplmn, dec_mcc_from_plmn, dec_mnc_from_plmn
25
26def hexstr_to_Nbytearr(s, nbytes):
27 return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2))]
28
29def format_xplmn_w_act(hexstr):
30 s = ""
31 for rec_data in hexstr_to_Nbytearr(hexstr, 5):
32 rec_info = dec_xplmn_w_act(rec_data)
33 if rec_info['mcc'] == "" and rec_info['mnc'] == "":
34 rec_str = "unused"
35 else:
36 rec_str = "MCC: %s MNC: %s AcT: %s" % (
37 rec_info['mcc'], rec_info['mnc'], ", ".join(rec_info['act']))
38 s += "\t%s # %s\n" % (rec_data, rec_str)
39 return s
40
41
42def format_xplmn(hexstr: Hexstr) -> str:
43 s = ""
44 for rec_data in hexstr_to_Nbytearr(hexstr, 3):
45 rec_info = dec_xplmn(rec_data)
46 if not rec_info['mcc'] and not rec_info['mnc']:
47 rec_str = "unused"
48 else:
49 rec_str = "MCC: %s MNC: %s" % (rec_info['mcc'], rec_info['mnc'])
50 s += "\t%s # %s\n" % (rec_data, rec_str)
51 return s
52
53
54def format_ePDGSelection(hexstr):
55 ePDGSelection_info_tag_chars = 2
56 ePDGSelection_info_tag_str = hexstr[:2]
57 s = ""
58 # Minimum length
59 len_chars = 2
60 # TODO: Need to determine length properly - definite length support only
61 # Inconsistency in spec: 3GPP TS 31.102 version 15.2.0 Release 15, 4.2.104
62 # As per spec, length is 5n, n - number of PLMNs
63 # But, each PLMN entry is made of PLMN (3 Bytes) + ePDG Priority (2 Bytes) + ePDG FQDN format (1 Byte)
64 # Totalling to 6 Bytes, maybe length should be 6n
65 len_str = hexstr[ePDGSelection_info_tag_chars:ePDGSelection_info_tag_chars+len_chars]
66
67 # Not programmed scenario
68 if int(len_str, 16) == 255 or int(ePDGSelection_info_tag_str, 16) == 255:
69 len_chars = 0
70 ePDGSelection_info_tag_chars = 0
71 if len_str[0] == '8':
72 # The bits 7 to 1 denotes the number of length octets if length > 127
73 if int(len_str[1]) > 0:
74 # Update number of length octets
75 len_chars = len_chars * int(len_str[1])
76 len_str = hexstr[ePDGSelection_info_tag_chars:len_chars]
77
78 content_str = hexstr[ePDGSelection_info_tag_chars+len_chars:]
79 # Right pad to prevent index out of range - multiple of 6 bytes
80 content_str = rpad(content_str, len(content_str) +
81 (12 - (len(content_str) % 12)))
82 for rec_data in hexstr_to_Nbytearr(content_str, 6):
83 rec_info = dec_ePDGSelection(rec_data)
84 if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
85 rec_str = "unused"
86 else:
87 rec_str = "MCC: %03d MNC: %03d ePDG Priority: %s ePDG FQDN format: %s" % \
88 (rec_info['mcc'], rec_info['mnc'],
89 rec_info['epdg_priority'], rec_info['epdg_fqdn_format'])
90 s += "\t%s # %s\n" % (rec_data, rec_str)
91 return s
92
93def enc_st(st, service, state=1):
94 """
95 Encodes the EF S/U/IST/EST and returns the updated Service Table
96
97 Parameters:
98 st - Current value of SIM/USIM/ISIM Service Table
99 service - Service Number to encode as activated/de-activated
100 state - 1 mean activate, 0 means de-activate
101
102 Returns:
103 s - Modified value of SIM/USIM/ISIM Service Table
104
105 Default values:
106 - state: 1 - Sets the particular Service bit to 1
107 """
108 st_bytes = [st[i:i+2] for i in range(0, len(st), 2)]
109
110 s = ""
111 # Check whether the requested service is present in each byte
112 for i in range(0, len(st_bytes)):
113 # Byte i contains info about Services num (8i+1) to num (8i+8)
114 if service in range((8*i) + 1, (8*i) + 9):
115 byte = int(st_bytes[i], 16)
116 # Services in each byte are in order MSB to LSB
117 # MSB - Service (8i+8)
118 # LSB - Service (8i+1)
119 mod_byte = 0x00
120 # Copy bit by bit contents of byte to mod_byte with modified bit
121 # for requested service
122 for j in range(1, 9):
123 mod_byte = mod_byte >> 1
124 if service == (8*i) + j:
125 mod_byte = state == 1 and mod_byte | 0x80 or mod_byte & 0x7f
126 else:
127 mod_byte = byte & 0x01 == 0x01 and mod_byte | 0x80 or mod_byte & 0x7f
128 byte = byte >> 1
129
130 s += ('%02x' % (mod_byte))
131 else:
132 s += st_bytes[i]
133
134 return s
135
136
137def dec_st(st, table="sim") -> str:
138 """
139 Parses the EF S/U/IST and prints the list of available services in EF S/U/IST
140 """
141
142 if table == "isim":
143 from pySim.ts_31_103 import EF_IST_map
144 lookup_map = EF_IST_map
145 elif table == "usim":
146 from pySim.ts_31_102 import EF_UST_map
147 lookup_map = EF_UST_map
148 else:
149 from pySim.ts_51_011 import EF_SST_map
150 lookup_map = EF_SST_map
151
152 st_bytes = [st[i:i+2] for i in range(0, len(st), 2)]
153
154 avail_st = ""
155 # Get each byte and check for available services
156 for i in range(0, len(st_bytes)):
157 # Byte i contains info about Services num (8i+1) to num (8i+8)
158 byte = int(st_bytes[i], 16)
159 # Services in each byte are in order MSB to LSB
160 # MSB - Service (8i+8)
161 # LSB - Service (8i+1)
162 for j in range(1, 9):
163 if byte & 0x01 == 0x01 and ((8*i) + j in lookup_map):
164 # Byte X contains info about Services num (8X-7) to num (8X)
165 # bit = 1: service available
166 # bit = 0: service not available
167 avail_st += '\tService %d - %s\n' % (
168 (8*i) + j, lookup_map[(8*i) + j])
169 byte = byte >> 1
170 return avail_st
171
172
173def enc_ePDGSelection(hexstr, mcc, mnc, epdg_priority='0001', epdg_fqdn_format='00'):
174 """
175 Encode ePDGSelection so it can be stored at EF.ePDGSelection or EF.ePDGSelectionEm.
176 See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
177
178 Default values:
179 - epdg_priority: '0001' - 1st Priority
180 - epdg_fqdn_format: '00' - Operator Identifier FQDN
181 """
182
183 plmn1 = enc_plmn(mcc, mnc) + epdg_priority + epdg_fqdn_format
184 # TODO: Handle encoding of Length field for length more than 127 Bytes
185 content = '80' + ('%02x' % (len(plmn1)//2)) + plmn1
186 content = rpad(content, len(hexstr))
187 return content
188
189
190def dec_ePDGSelection(sixhexbytes):
191 """
192 Decode ePDGSelection to get EF.ePDGSelection or EF.ePDGSelectionEm.
193 See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
194 """
195
196 res = {'mcc': 0, 'mnc': 0, 'epdg_priority': 0, 'epdg_fqdn_format': ''}
197 plmn_chars = 6
198 epdg_priority_chars = 4
199 epdg_fqdn_format_chars = 2
200 # first three bytes (six ascii hex chars)
201 plmn_str = sixhexbytes[:plmn_chars]
202 # two bytes after first three bytes
203 epdg_priority_str = sixhexbytes[plmn_chars:plmn_chars +
204 epdg_priority_chars]
205 # one byte after first five bytes
206 epdg_fqdn_format_str = sixhexbytes[plmn_chars +
207 epdg_priority_chars:plmn_chars + epdg_priority_chars + epdg_fqdn_format_chars]
208 res['mcc'] = dec_mcc_from_plmn(plmn_str)
209 res['mnc'] = dec_mnc_from_plmn(plmn_str)
210 res['epdg_priority'] = epdg_priority_str
211 res['epdg_fqdn_format'] = epdg_fqdn_format_str == '00' and 'Operator Identifier FQDN' or 'Location based FQDN'
212 return res