Compare commits
56 Commits
sysmocom/f
...
1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
289fd28091 | ||
|
|
92bdd5e901 | ||
|
|
c8caec2933 | ||
|
|
bdf3d3597b | ||
|
|
cebf8b198b | ||
|
|
06a1256b67 | ||
|
|
be3b64167a | ||
|
|
a97944b6ca | ||
|
|
c60192375e | ||
|
|
be7007e1d9 | ||
|
|
a5bd9684d3 | ||
|
|
0c02d8a57b | ||
|
|
3f67f9c1d3 | ||
|
|
28484d03e3 | ||
|
|
1279085f7e | ||
|
|
c491dc019f | ||
|
|
43fd03b627 | ||
|
|
654eca72c9 | ||
|
|
4779034f9e | ||
|
|
79f43dda3d | ||
|
|
556b0fe262 | ||
|
|
44e046240e | ||
|
|
05b2807168 | ||
|
|
cf727f2733 | ||
|
|
5ad9aec98f | ||
|
|
75c14c0cbd | ||
|
|
b0c7d121d7 | ||
|
|
ecbada993d | ||
|
|
3b342c2f14 | ||
|
|
acc222f9f0 | ||
|
|
f964df4eb5 | ||
|
|
3a261d31d5 | ||
|
|
5e67d5b80a | ||
|
|
3b00dbf0d2 | ||
|
|
95ec772b61 | ||
|
|
99d55552d5 | ||
|
|
95b4e8d4fa | ||
|
|
5d8cd9b378 | ||
|
|
dd014ea306 | ||
|
|
677d41bb41 | ||
|
|
de07b95f84 | ||
|
|
4a3580b4c1 | ||
|
|
f8232db327 | ||
|
|
5d0a30c19c | ||
|
|
3409ae7eea | ||
|
|
45fa604834 | ||
|
|
f394853533 | ||
|
|
d84daa12c2 | ||
|
|
dfe3dbb117 | ||
|
|
a562ea0351 | ||
|
|
4d9e6beaed | ||
|
|
8e0fccdbf3 | ||
|
|
71e38482e1 | ||
|
|
1a13c44200 | ||
|
|
8016405994 | ||
|
|
0f247f8766 |
@@ -40,8 +40,8 @@ pysim requires:
|
||||
|
||||
Example for Debian:
|
||||
|
||||
apt-get install python-pyscard python-serial python-pip
|
||||
pip install pytlv
|
||||
apt-get install python3-pyscard python3-serial python3-pip python3-yaml
|
||||
pip3 install pytlv
|
||||
|
||||
|
||||
Mailing List
|
||||
|
||||
@@ -9,7 +9,7 @@ if [ ! -d "./pysim-testdata/" ] ; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
virtualenv -p python2 venv --system-site-packages
|
||||
virtualenv -p python3 venv --system-site-packages
|
||||
. venv/bin/activate
|
||||
pip install pytlv
|
||||
pip install pyyaml
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Utility to deal with sim cards and program the 'magic' ones easily
|
||||
@@ -147,6 +147,24 @@ def parse_options():
|
||||
parser.add_option("--acc", dest="acc",
|
||||
help="Set ACC bits (Access Control Code). not all card types are supported",
|
||||
)
|
||||
parser.add_option("--epdgid", dest="epdgid",
|
||||
help="Set Home Evolved Packet Data Gateway (ePDG) Identifier. (Only FQDN format supported)",
|
||||
)
|
||||
parser.add_option("--epdgSelection", dest="epdgSelection",
|
||||
help="Set PLMN for ePDG Selection Information. (Only Operator Identifier FQDN format supported)",
|
||||
)
|
||||
parser.add_option("--pcscf", dest="pcscf",
|
||||
help="Set Proxy Call Session Control Function (P-CSCF) Address. (Only FQDN format supported)",
|
||||
)
|
||||
parser.add_option("--ims-hdomain", dest="ims_hdomain",
|
||||
help="Set IMS Home Network Domain Name in FQDN format",
|
||||
)
|
||||
parser.add_option("--impi", dest="impi",
|
||||
help="Set IMS private user identity",
|
||||
)
|
||||
parser.add_option("--impu", dest="impu",
|
||||
help="Set IMS public user identity",
|
||||
)
|
||||
parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
|
||||
help="Read the IMSI from the CARD", default=False
|
||||
)
|
||||
@@ -222,8 +240,9 @@ def parse_options():
|
||||
|
||||
|
||||
def _digits(secret, usage, len, num):
|
||||
s = hashlib.sha1(secret + usage + '%d' % num)
|
||||
d = ''.join(['%02d'%ord(x) for x in s.digest()])
|
||||
seed = secret + usage + '%d' % num
|
||||
s = hashlib.sha1(seed.encode())
|
||||
d = ''.join(['%02d' % x for x in s.digest()])
|
||||
return d[0:len]
|
||||
|
||||
def _mcc_mnc_digits(mcc, mnc):
|
||||
@@ -257,7 +276,7 @@ def _dbi_binary_quote(s):
|
||||
m = sum_
|
||||
e = i
|
||||
if m == 0: # No overhead ? use this !
|
||||
break;
|
||||
break
|
||||
|
||||
# Generate output
|
||||
out = []
|
||||
@@ -300,7 +319,7 @@ def gen_parameters(opts):
|
||||
|
||||
if opts.name is not None:
|
||||
if len(opts.name) > 16:
|
||||
raise ValueError('Service Provider Name must max 16 characters!');
|
||||
raise ValueError('Service Provider Name must max 16 characters!')
|
||||
|
||||
if opts.msisdn is not None:
|
||||
msisdn = opts.msisdn
|
||||
@@ -317,7 +336,7 @@ def gen_parameters(opts):
|
||||
if opts.iccid is not None:
|
||||
iccid = opts.iccid
|
||||
if not _isnum(iccid, 19) and not _isnum(iccid, 20):
|
||||
raise ValueError('ICCID must be 19 or 20 digits !');
|
||||
raise ValueError('ICCID must be 19 or 20 digits !')
|
||||
|
||||
else:
|
||||
if opts.num is None:
|
||||
@@ -429,6 +448,15 @@ def gen_parameters(opts):
|
||||
|
||||
pin_adm = sanitize_pin_adm(opts)
|
||||
|
||||
# ePDG Selection Information
|
||||
if opts.epdgSelection:
|
||||
if len(opts.epdgSelection) < 5 or len(opts.epdgSelection) > 6:
|
||||
raise ValueError('ePDG Selection Information is not valid')
|
||||
epdg_mcc = opts.epdgSelection[:3]
|
||||
epdg_mnc = opts.epdgSelection[3:]
|
||||
if not epdg_mcc.isdigit() or not epdg_mnc.isdigit():
|
||||
raise ValueError('PLMN for ePDG Selection must only contain decimal digits')
|
||||
|
||||
# Return that
|
||||
return {
|
||||
'name' : opts.name,
|
||||
@@ -442,6 +470,12 @@ def gen_parameters(opts):
|
||||
'acc' : acc,
|
||||
'pin_adm' : pin_adm,
|
||||
'msisdn' : opts.msisdn,
|
||||
'epdgid' : opts.epdgid,
|
||||
'epdgSelection' : opts.epdgSelection,
|
||||
'pcscf' : opts.pcscf,
|
||||
'ims_hdomain': opts.ims_hdomain,
|
||||
'impi' : opts.impi,
|
||||
'impu' : opts.impu,
|
||||
}
|
||||
|
||||
|
||||
@@ -488,15 +522,15 @@ def _read_params_csv(opts, iccid=None, imsi=None):
|
||||
if opts.num is not None and opts.read_iccid is False and opts.read_imsi is False:
|
||||
if opts.num == i:
|
||||
f.close()
|
||||
return row;
|
||||
return row
|
||||
i += 1
|
||||
if row['iccid'] == iccid:
|
||||
f.close()
|
||||
return row;
|
||||
return row
|
||||
|
||||
if row['imsi'] == imsi:
|
||||
f.close()
|
||||
return row;
|
||||
return row
|
||||
|
||||
f.close()
|
||||
return None
|
||||
@@ -643,13 +677,13 @@ def process_card(opts, first, card_handler):
|
||||
if opts.read_iccid:
|
||||
if opts.dry_run:
|
||||
# Connect transport
|
||||
card_handler.get(false)
|
||||
card_handler.get(False)
|
||||
(res,_) = scc.read_binary(['3f00', '2fe2'], length=10)
|
||||
iccid = dec_iccid(res)
|
||||
elif opts.read_imsi:
|
||||
if opts.dry_run:
|
||||
# Connect transport
|
||||
card_handler.get(false)
|
||||
card_handler.get(False)
|
||||
(res,_) = scc.read_binary(EF['IMSI'])
|
||||
imsi = swap_nibbles(res)[3:]
|
||||
else:
|
||||
@@ -686,6 +720,8 @@ if __name__ == '__main__':
|
||||
|
||||
# Init card reader driver
|
||||
sl = init_reader(opts)
|
||||
if sl is None:
|
||||
exit(1)
|
||||
|
||||
# Create command layer
|
||||
scc = SimCardCommands(transport=sl)
|
||||
|
||||
124
pySim-read.py
124
pySim-read.py
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#
|
||||
# Utility to display some informations about a SIM card
|
||||
@@ -28,14 +28,15 @@ import os
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
from pySim.ts_51_011 import EF, DF, EF_SST_map
|
||||
from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD_mode_map
|
||||
from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map
|
||||
from pySim.ts_31_103 import EF_IST_map
|
||||
from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map
|
||||
|
||||
from pySim.commands import SimCardCommands
|
||||
from pySim.cards import card_detect, Card
|
||||
from pySim.cards import card_detect, Card, UsimCard, IsimCard
|
||||
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn
|
||||
from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_epdgid
|
||||
from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_addr_tlv
|
||||
from pySim.utils import h2s, format_ePDGSelection
|
||||
|
||||
def parse_options():
|
||||
|
||||
@@ -81,6 +82,8 @@ if __name__ == '__main__':
|
||||
|
||||
# Init card reader driver
|
||||
sl = init_reader(opts)
|
||||
if sl is None:
|
||||
exit(1)
|
||||
|
||||
# Create command layer
|
||||
scc = SimCardCommands(transport=sl)
|
||||
@@ -225,7 +228,15 @@ if __name__ == '__main__':
|
||||
# EF.AD
|
||||
(res, sw) = card.read_binary('AD')
|
||||
if sw == '9000':
|
||||
print("AD: %s" % (res,))
|
||||
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:
|
||||
print("\tCiphering Indicator: enabled")
|
||||
else:
|
||||
print("\tCiphering Indicator: disabled")
|
||||
else:
|
||||
print("AD: Can't read, response code = %s" % (sw,))
|
||||
|
||||
@@ -241,33 +252,104 @@ if __name__ == '__main__':
|
||||
# Check whether we have th AID of USIM, if so select it by its AID
|
||||
# EF.UST - File Id in ADF USIM : 6f38
|
||||
if '9000' == card.select_adf_by_aid():
|
||||
# Select USIM profile
|
||||
usim_card = UsimCard(scc)
|
||||
|
||||
# EF.EHPLMN
|
||||
if card.file_exists(EF_USIM_ADF_map['EHPLMN']):
|
||||
(res, sw) = card.read_ehplmn()
|
||||
if usim_card.file_exists(EF_USIM_ADF_map['EHPLMN']):
|
||||
(res, sw) = usim_card.read_ehplmn()
|
||||
if sw == '9000':
|
||||
print("EHPLMN:\n%s" % (res))
|
||||
else:
|
||||
print("EHPLMN: Can't read, response code = %s" % (sw,))
|
||||
|
||||
# EF.UST
|
||||
(res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
|
||||
if sw == '9000':
|
||||
print("USIM Service Table: %s" % res)
|
||||
# Print those which are available
|
||||
print("%s" % dec_st(res, table="usim"))
|
||||
else:
|
||||
print("USIM Service Table: Can't read, response code = %s" % (sw,))
|
||||
try:
|
||||
if usim_card.file_exists(EF_USIM_ADF_map['UST']):
|
||||
# res[0] - EF content of UST
|
||||
# res[1] - Human readable format of services marked available in UST
|
||||
(res, sw) = usim_card.read_ust()
|
||||
if sw == '9000':
|
||||
print("USIM Service Table: %s" % res[0])
|
||||
print("%s" % res[1])
|
||||
else:
|
||||
print("USIM Service Table: Can't read, response code = %s" % (sw,))
|
||||
except Exception as e:
|
||||
print("USIM Service Table: Can't read file -- " + str(e))
|
||||
|
||||
#EF.ePDGId - Home ePDG Identifier
|
||||
try:
|
||||
(res, sw) = card.read_binary(EF_USIM_ADF_map['ePDGId'])
|
||||
if sw == '9000':
|
||||
content = dec_epdgid(res)
|
||||
print("ePDGId:\n%s" % (len(content) and content or '\tNot available\n',))
|
||||
else:
|
||||
print("ePDGId: Can't read, response code = %s" % (sw,))
|
||||
if usim_card.file_exists(EF_USIM_ADF_map['ePDGId']):
|
||||
(res, sw) = usim_card.read_epdgid()
|
||||
if sw == '9000':
|
||||
print("ePDGId:\n%s" % (len(res) and res or '\tNot available\n',))
|
||||
else:
|
||||
print("ePDGId: Can't read, response code = %s" % (sw,))
|
||||
except Exception as e:
|
||||
print("ePDGId: Can't read file -- " + str(e))
|
||||
|
||||
#EF.ePDGSelection - ePDG Selection Information
|
||||
try:
|
||||
if usim_card.file_exists(EF_USIM_ADF_map['ePDGSelection']):
|
||||
(res, sw) = usim_card.read_ePDGSelection()
|
||||
if sw == '9000':
|
||||
print("ePDGSelection:\n%s" % (res,))
|
||||
else:
|
||||
print("ePDGSelection: Can't read, response code = %s" % (sw,))
|
||||
except Exception as e:
|
||||
print("ePDGSelection: Can't read file -- " + str(e))
|
||||
|
||||
# Select ISIM application by its AID
|
||||
if '9000' == card.select_adf_by_aid(adf="isim"):
|
||||
# Select USIM profile
|
||||
isim_card = IsimCard(scc)
|
||||
|
||||
#EF.P-CSCF - P-CSCF Address
|
||||
try:
|
||||
if isim_card.file_exists(EF_ISIM_ADF_map['PCSCF']):
|
||||
res = isim_card.read_pcscf()
|
||||
print("P-CSCF:\n%s" % (len(res) and res or '\tNot available\n',))
|
||||
except Exception as e:
|
||||
print("P-CSCF: Can't read file -- " + str(e))
|
||||
|
||||
# EF.DOMAIN - Home Network Domain Name e.g. ims.mncXXX.mccXXX.3gppnetwork.org
|
||||
try:
|
||||
if isim_card.file_exists(EF_ISIM_ADF_map['DOMAIN']):
|
||||
(res, sw) = isim_card.read_domain()
|
||||
if sw == '9000':
|
||||
print("Home Network Domain Name: %s" % (len(res) and res or 'Not available',))
|
||||
else:
|
||||
print("Home Network Domain Name: Can't read, response code = %s" % (sw,))
|
||||
except Exception as e:
|
||||
print("Home Network Domain Name: Can't read file -- " + str(e))
|
||||
|
||||
# EF.IMPI - IMS private user identity
|
||||
try:
|
||||
if isim_card.file_exists(EF_ISIM_ADF_map['IMPI']):
|
||||
(res, sw) = isim_card.read_impi()
|
||||
if sw == '9000':
|
||||
print("IMS private user identity: %s" % (len(res) and res or 'Not available',))
|
||||
else:
|
||||
print("IMS private user identity: Can't read, response code = %s" % (sw,))
|
||||
except Exception as e:
|
||||
print("IMS private user identity: Can't read file -- " + str(e))
|
||||
|
||||
# EF.IMPU - IMS public user identity
|
||||
try:
|
||||
if isim_card.file_exists(EF_ISIM_ADF_map['IMPU']):
|
||||
res = isim_card.read_impu()
|
||||
print("IMS public user identity:\n%s" % (len(res) and res or '\tNot available\n',))
|
||||
except Exception as e:
|
||||
print("IMS public user identity: Can't read file -- " + str(e))
|
||||
|
||||
# EF.UICCIARI - UICC IARI
|
||||
try:
|
||||
if isim_card.file_exists(EF_ISIM_ADF_map['UICCIARI']):
|
||||
res = isim_card.read_iari()
|
||||
print("UICC IARI:\n%s" % (len(res) and res or '\tNot available\n',))
|
||||
except Exception as e:
|
||||
print("UICC IARI: Can't read file -- " + str(e))
|
||||
|
||||
# Check whether we have th AID of ISIM, if so select it by its AID
|
||||
# EF.IST - File Id in ADF ISIM : 6f07
|
||||
if '9000' == card.select_adf_by_aid(adf="isim"):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
""" pySim: card handler utilities
|
||||
|
||||
330
pySim/cards.py
330
pySim/cards.py
@@ -25,8 +25,10 @@
|
||||
|
||||
from pySim.ts_51_011 import EF, DF
|
||||
from pySim.ts_31_102 import EF_USIM_ADF_map
|
||||
from pySim.ts_31_103 import EF_ISIM_ADF_map
|
||||
from pySim.utils import *
|
||||
from smartcard.util import toBytes
|
||||
from pytlv.TLV import *
|
||||
|
||||
class Card(object):
|
||||
|
||||
@@ -204,30 +206,6 @@ class Card(object):
|
||||
else:
|
||||
return (None, sw)
|
||||
|
||||
# Read the (full) AID for either ISIM or USIM or ISIM application
|
||||
def read_aid(self, isim = False):
|
||||
|
||||
# First (known) halves of the AID
|
||||
aid_usim = "a0000000871002"
|
||||
aid_isim = "a0000000871004"
|
||||
|
||||
# Select which one to look for
|
||||
if isim:
|
||||
aid = aid_isim
|
||||
else:
|
||||
aid = aid_usim
|
||||
|
||||
# Find out how many records the EF.DIR has, then go through
|
||||
# all records and try to find the AID we are looking for
|
||||
aid_record_count = self._scc.record_count(['2F00'])
|
||||
for i in range(0, aid_record_count):
|
||||
record = self._scc.read_record(['2F00'], i + 1)
|
||||
if aid in record[0]:
|
||||
aid_len = int(record[0][6:8], 16)
|
||||
return record[0][8:8 + aid_len * 2]
|
||||
|
||||
return None
|
||||
|
||||
# Fetch all the AIDs present on UICC
|
||||
def read_aids(self):
|
||||
try:
|
||||
@@ -288,7 +266,177 @@ class UsimCard(Card):
|
||||
data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
|
||||
return sw
|
||||
|
||||
def read_epdgid(self):
|
||||
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
|
||||
if sw == '9000':
|
||||
return (dec_addr_tlv(res), sw)
|
||||
else:
|
||||
return (None, sw)
|
||||
|
||||
def update_epdgid(self, epdgid):
|
||||
size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
|
||||
if len(epdgid) > 0:
|
||||
addr_type = get_addr_type(epdgid)
|
||||
if addr_type == None:
|
||||
raise ValueError("Unknown ePDG Id address type or invalid address provided")
|
||||
epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
|
||||
else:
|
||||
epdgid_tlv = rpad('ff', size)
|
||||
data, sw = self._scc.update_binary(
|
||||
EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
|
||||
return sw
|
||||
|
||||
def read_ePDGSelection(self):
|
||||
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
|
||||
if sw == '9000':
|
||||
return (format_ePDGSelection(res), sw)
|
||||
else:
|
||||
return (None, sw)
|
||||
|
||||
def update_ePDGSelection(self, mcc, mnc):
|
||||
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
|
||||
if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
|
||||
# Reset contents
|
||||
# 80 - Tag value
|
||||
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
|
||||
elif sw == '9000':
|
||||
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
|
||||
return sw
|
||||
|
||||
def read_ust(self):
|
||||
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
|
||||
if sw == '9000':
|
||||
# Print those which are available
|
||||
return ([res, dec_st(res, table="usim")], sw)
|
||||
else:
|
||||
return ([None, None], sw)
|
||||
|
||||
def update_ust(self, service, bit=1):
|
||||
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
|
||||
if sw == '9000':
|
||||
content = enc_st(res, service, bit)
|
||||
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['UST'], content)
|
||||
return sw
|
||||
|
||||
class IsimCard(Card):
|
||||
def __init__(self, ssc):
|
||||
super(IsimCard, self).__init__(ssc)
|
||||
|
||||
def read_pcscf(self):
|
||||
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
|
||||
pcscf_recs = ""
|
||||
for i in range(0, rec_cnt):
|
||||
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
|
||||
if sw == '9000':
|
||||
content = dec_addr_tlv(res)
|
||||
pcscf_recs += "%s" % (len(content) and content or '\tNot available\n')
|
||||
else:
|
||||
pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (sw)
|
||||
return pcscf_recs
|
||||
|
||||
def update_pcscf(self, pcscf):
|
||||
if len(pcscf) > 0:
|
||||
addr_type = get_addr_type(pcscf)
|
||||
if addr_type == None:
|
||||
raise ValueError("Unknown PCSCF address type or invalid address provided")
|
||||
content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
|
||||
else:
|
||||
# Just the tag value
|
||||
content = '80'
|
||||
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
|
||||
pcscf_tlv = rpad(content, rec_size_bytes*2)
|
||||
data, sw = self._scc.update_record(EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
|
||||
return sw
|
||||
|
||||
def read_domain(self):
|
||||
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
|
||||
if sw == '9000':
|
||||
# Skip the inital tag value ('80') byte and get length of contents
|
||||
length = int(res[2:4], 16)
|
||||
content = h2s(res[4:4+(length*2)])
|
||||
return (content, sw)
|
||||
else:
|
||||
return (None, sw)
|
||||
|
||||
def update_domain(self, domain=None, mcc=None, mnc=None):
|
||||
hex_str = ""
|
||||
if domain:
|
||||
hex_str = s2h(domain)
|
||||
elif mcc and mnc:
|
||||
# MCC and MNC always has 3 digits in domain form
|
||||
plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
|
||||
hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
|
||||
|
||||
# Build TLV
|
||||
tlv = TLV(['80'])
|
||||
content = tlv.build({'80': hex_str})
|
||||
|
||||
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
|
||||
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
|
||||
return sw
|
||||
|
||||
def read_impi(self):
|
||||
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
|
||||
if sw == '9000':
|
||||
# Skip the inital tag value ('80') byte and get length of contents
|
||||
length = int(res[2:4], 16)
|
||||
content = h2s(res[4:4+(length*2)])
|
||||
return (content, sw)
|
||||
else:
|
||||
return (None, sw)
|
||||
|
||||
def update_impi(self, impi=None):
|
||||
hex_str = ""
|
||||
if impi:
|
||||
hex_str = s2h(impi)
|
||||
# Build TLV
|
||||
tlv = TLV(['80'])
|
||||
content = tlv.build({'80': hex_str})
|
||||
|
||||
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
|
||||
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
|
||||
return sw
|
||||
|
||||
def read_impu(self):
|
||||
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
|
||||
impu_recs = ""
|
||||
for i in range(0, rec_cnt):
|
||||
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
|
||||
if sw == '9000':
|
||||
# Skip the inital tag value ('80') byte and get length of contents
|
||||
length = int(res[2:4], 16)
|
||||
content = h2s(res[4:4+(length*2)])
|
||||
impu_recs += "\t%s\n" % (len(content) and content or 'Not available')
|
||||
else:
|
||||
impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (sw)
|
||||
return impu_recs
|
||||
|
||||
def update_impu(self, impu=None):
|
||||
hex_str = ""
|
||||
if impu:
|
||||
hex_str = s2h(impu)
|
||||
# Build TLV
|
||||
tlv = TLV(['80'])
|
||||
content = tlv.build({'80': hex_str})
|
||||
|
||||
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
|
||||
impu_tlv = rpad(content, rec_size_bytes*2)
|
||||
data, sw = self._scc.update_record(EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
|
||||
return sw
|
||||
|
||||
def read_iari(self):
|
||||
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
|
||||
uiari_recs = ""
|
||||
for i in range(0, rec_cnt):
|
||||
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['UICCIARI'], i + 1)
|
||||
if sw == '9000':
|
||||
# Skip the inital tag value ('80') byte and get length of contents
|
||||
length = int(res[2:4], 16)
|
||||
content = h2s(res[4:4+(length*2)])
|
||||
uiari_recs += "\t%s\n" % (len(content) and content or 'Not available')
|
||||
else:
|
||||
uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (sw)
|
||||
return uiari_recs
|
||||
|
||||
class _MagicSimBase(Card):
|
||||
"""
|
||||
@@ -333,7 +481,7 @@ class _MagicSimBase(Card):
|
||||
r = self._scc.select_file(['3f00', '7f4d', f[0]])
|
||||
rec_len = int(r[-1][28:30], 16)
|
||||
tlen = int(r[-1][4:8],16)
|
||||
rec_cnt = (tlen / rec_len) - 1;
|
||||
rec_cnt = (tlen / rec_len) - 1
|
||||
|
||||
if (rec_cnt < 1) or (rec_len != f[1]):
|
||||
raise RuntimeError('Bad card type')
|
||||
@@ -463,7 +611,7 @@ class FakeMagicSim(Card):
|
||||
r = self._scc.select_file(['3f00', '000c'])
|
||||
rec_len = int(r[-1][28:30], 16)
|
||||
tlen = int(r[-1][4:8],16)
|
||||
rec_cnt = (tlen / rec_len) - 1;
|
||||
rec_cnt = (tlen / rec_len) - 1
|
||||
|
||||
if (rec_cnt < 1) or (rec_len != 0x5a):
|
||||
raise RuntimeError('Bad card type')
|
||||
@@ -624,9 +772,9 @@ class SysmoSIMgr2(Card):
|
||||
|
||||
def program(self, p):
|
||||
|
||||
# select MF
|
||||
# select MF
|
||||
r = self._scc.select_file(['3f00'])
|
||||
|
||||
|
||||
# authenticate as SUPER ADM using default key
|
||||
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
|
||||
|
||||
@@ -642,7 +790,7 @@ class SysmoSIMgr2(Card):
|
||||
|
||||
pdu = 'A0D43A0508' + b2h(pin)
|
||||
data, sw = self._scc._tp.send_apdu(pdu)
|
||||
|
||||
|
||||
# authenticate as ADM (enough to write file, and can set PINs)
|
||||
|
||||
self._scc.verify_chv(0x05, pin)
|
||||
@@ -652,7 +800,7 @@ class SysmoSIMgr2(Card):
|
||||
|
||||
# select DF_GSM
|
||||
r = self._scc.select_file(['7f20'])
|
||||
|
||||
|
||||
# write EF.IMSI
|
||||
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
||||
|
||||
@@ -674,7 +822,7 @@ class SysmoSIMgr2(Card):
|
||||
|
||||
# select DF_TELECOM
|
||||
r = self._scc.select_file(['3f00', '7f10'])
|
||||
|
||||
|
||||
# write EF.SMSP
|
||||
if p.get('smsp'):
|
||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
||||
@@ -784,7 +932,7 @@ class SysmoUSIMSJS1(UsimCard):
|
||||
data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
|
||||
|
||||
|
||||
class FairwavesSIM(Card):
|
||||
class FairwavesSIM(UsimCard):
|
||||
"""
|
||||
FairwavesSIM
|
||||
|
||||
@@ -973,7 +1121,7 @@ class OpenCellsSim(Card):
|
||||
# write EF.IMSI
|
||||
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
||||
|
||||
class WavemobileSim(Card):
|
||||
class WavemobileSim(UsimCard):
|
||||
"""
|
||||
WavemobileSim
|
||||
|
||||
@@ -1064,7 +1212,7 @@ class WavemobileSim(Card):
|
||||
return None
|
||||
|
||||
|
||||
class SysmoISIMSJA2(UsimCard):
|
||||
class SysmoISIMSJA2(UsimCard, IsimCard):
|
||||
"""
|
||||
sysmocom sysmoISIM-SJA2
|
||||
"""
|
||||
@@ -1152,6 +1300,26 @@ class SysmoISIMSJA2(UsimCard):
|
||||
r = self._scc.select_file(['3f00', '7f10'])
|
||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
|
||||
|
||||
# EF.MSISDN
|
||||
# TODO: Alpha Identifier (currently 'ff'O * 20)
|
||||
# TODO: Capability/Configuration1 Record Identifier
|
||||
# TODO: Extension1 Record Identifier
|
||||
if p.get('msisdn') is not None:
|
||||
msisdn = enc_msisdn(p['msisdn'])
|
||||
content = 'ff' * 20 + msisdn + 'ff' * 2
|
||||
|
||||
r = self._scc.select_file(['3f00', '7f10'])
|
||||
data, sw = self._scc.update_record('6F40', 1, content, force_len=True)
|
||||
|
||||
# EF.ACC
|
||||
if p.get('acc'):
|
||||
sw = self.update_acc(p['acc'])
|
||||
if sw != '9000':
|
||||
print("Programming ACC failed with code %s"%sw)
|
||||
|
||||
# Populate AIDs
|
||||
self.read_aids()
|
||||
|
||||
# update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
|
||||
# hard linked to EF-USIM_AUTH_KEY)
|
||||
self._scc.select_file(['3f00'])
|
||||
@@ -1162,20 +1330,55 @@ class SysmoISIMSJA2(UsimCard):
|
||||
self._scc.update_binary('6f20', p['opc'], 17)
|
||||
|
||||
# update EF-USIM_AUTH_KEY in ADF.ISIM
|
||||
self._scc.select_file(['3f00'])
|
||||
aid = self.read_aid(isim = True)
|
||||
if (aid):
|
||||
self._scc.select_adf(aid)
|
||||
if '9000' == self.select_adf_by_aid(adf="isim"):
|
||||
if p.get('ki'):
|
||||
self._scc.update_binary('af20', p['ki'], 1)
|
||||
if p.get('opc'):
|
||||
self._scc.update_binary('af20', p['opc'], 17)
|
||||
|
||||
self._scc.select_file(['3f00'])
|
||||
aid = self.read_aid()
|
||||
if (aid):
|
||||
# update EF.P-CSCF in ADF.ISIM
|
||||
if self.file_exists(EF_ISIM_ADF_map['PCSCF']):
|
||||
if p.get('pcscf'):
|
||||
sw = self.update_pcscf(p['pcscf'])
|
||||
else:
|
||||
sw = self.update_pcscf("")
|
||||
if sw != '9000':
|
||||
print("Programming P-CSCF failed with code %s"%sw)
|
||||
|
||||
|
||||
# update EF.DOMAIN in ADF.ISIM
|
||||
if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
|
||||
if p.get('ims_hdomain'):
|
||||
sw = self.update_domain(domain=p['ims_hdomain'])
|
||||
else:
|
||||
sw = self.update_domain()
|
||||
|
||||
if sw != '9000':
|
||||
print("Programming Home Network Domain Name failed with code %s"%sw)
|
||||
|
||||
# update EF.IMPI in ADF.ISIM
|
||||
# TODO: Validate IMPI input
|
||||
if self.file_exists(EF_ISIM_ADF_map['IMPI']):
|
||||
if p.get('impi'):
|
||||
sw = self.update_impi(p['impi'])
|
||||
else:
|
||||
sw = self.update_impi()
|
||||
if sw != '9000':
|
||||
print("Programming IMPI failed with code %s"%sw)
|
||||
|
||||
# update EF.IMPU in ADF.ISIM
|
||||
# TODO: Validate IMPU input
|
||||
# Support multiple IMPU if there is enough space
|
||||
if self.file_exists(EF_ISIM_ADF_map['IMPU']):
|
||||
if p.get('impu'):
|
||||
sw = self.update_impu(p['impu'])
|
||||
else:
|
||||
sw = self.update_impu()
|
||||
if sw != '9000':
|
||||
print("Programming IMPU failed with code %s"%sw)
|
||||
|
||||
if '9000' == self.select_adf_by_aid():
|
||||
# update EF-USIM_AUTH_KEY in ADF.USIM
|
||||
self._scc.select_adf(aid)
|
||||
if p.get('ki'):
|
||||
self._scc.update_binary('af20', p['ki'], 1)
|
||||
if p.get('opc'):
|
||||
@@ -1187,6 +1390,49 @@ class SysmoISIMSJA2(UsimCard):
|
||||
sw = self.update_ehplmn(p['mcc'], p['mnc'])
|
||||
if sw != '9000':
|
||||
print("Programming EHPLMN failed with code %s"%sw)
|
||||
|
||||
# update EF.ePDGId in ADF.USIM
|
||||
if self.file_exists(EF_USIM_ADF_map['ePDGId']):
|
||||
if p.get('epdgid'):
|
||||
sw = self.update_epdgid(p['epdgid'])
|
||||
else:
|
||||
sw = self.update_epdgid("")
|
||||
if sw != '9000':
|
||||
print("Programming ePDGId failed with code %s"%sw)
|
||||
|
||||
# update EF.ePDGSelection in ADF.USIM
|
||||
if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
|
||||
if p.get('epdgSelection'):
|
||||
epdg_plmn = p['epdgSelection']
|
||||
sw = self.update_ePDGSelection(epdg_plmn[:3], epdg_plmn[3:])
|
||||
else:
|
||||
sw = self.update_ePDGSelection("", "")
|
||||
if sw != '9000':
|
||||
print("Programming ePDGSelection failed with code %s"%sw)
|
||||
|
||||
|
||||
# After successfully programming EF.ePDGId and EF.ePDGSelection,
|
||||
# Set service 106 and 107 as available in EF.UST
|
||||
# Disable service 95, 99, 115 if ISIM application is present
|
||||
if self.file_exists(EF_USIM_ADF_map['UST']):
|
||||
if p.get('epdgSelection') and p.get('epdgid'):
|
||||
sw = self.update_ust(106, 1)
|
||||
if sw != '9000':
|
||||
print("Programming UST failed with code %s"%sw)
|
||||
sw = self.update_ust(107, 1)
|
||||
if sw != '9000':
|
||||
print("Programming UST failed with code %s"%sw)
|
||||
|
||||
sw = self.update_ust(95, 0)
|
||||
if sw != '9000':
|
||||
print("Programming UST failed with code %s"%sw)
|
||||
sw = self.update_ust(99, 0)
|
||||
if sw != '9000':
|
||||
print("Programming UST failed with code %s"%sw)
|
||||
sw = self.update_ust(115, 0)
|
||||
if sw != '9000':
|
||||
print("Programming UST failed with code %s"%sw)
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from pySim.utils import rpad, b2h
|
||||
|
||||
class SimCardCommands(object):
|
||||
def __init__(self, transport):
|
||||
self._tp = transport;
|
||||
self._tp = transport
|
||||
self._cla_byte = "a0"
|
||||
self.sel_ctrl = "0000"
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
|
||||
from smartcard.CardConnection import CardConnection
|
||||
from smartcard.CardRequest import CardRequest
|
||||
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
|
||||
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException, CardConnectionException
|
||||
from smartcard.System import readers
|
||||
|
||||
from pySim.exceptions import NoCardError
|
||||
from pySim.exceptions import NoCardError, ProtocolError
|
||||
from pySim.transport import LinkBase
|
||||
from pySim.utils import h2i, i2h
|
||||
|
||||
@@ -35,7 +35,7 @@ from pySim.utils import h2i, i2h
|
||||
class PcscSimLink(LinkBase):
|
||||
|
||||
def __init__(self, reader_number=0):
|
||||
r = readers();
|
||||
r = readers()
|
||||
self._reader = r[reader_number]
|
||||
self._con = self._reader.createConnection()
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ from __future__ import absolute_import
|
||||
|
||||
import serial
|
||||
import time
|
||||
import os.path
|
||||
|
||||
from pySim.exceptions import NoCardError, ProtocolError
|
||||
from pySim.transport import LinkBase
|
||||
@@ -34,6 +35,8 @@ from pySim.utils import h2b, b2h
|
||||
class SerialSimLink(LinkBase):
|
||||
|
||||
def __init__(self, device='/dev/ttyUSB0', baudrate=9600, rst='-rts', debug=False):
|
||||
if not os.path.exists(device):
|
||||
raise ValueError("device file %s does not exist -- abort" % device)
|
||||
self._sl = serial.Serial(
|
||||
port = device,
|
||||
parity = serial.PARITY_EVEN,
|
||||
@@ -49,7 +52,8 @@ class SerialSimLink(LinkBase):
|
||||
self._atr = None
|
||||
|
||||
def __del__(self):
|
||||
self._sl.close()
|
||||
if (hasattr(self, "_sl")):
|
||||
self._sl.close()
|
||||
|
||||
def wait_for_card(self, timeout=None, newcardonly=False):
|
||||
# Direct try
|
||||
@@ -117,7 +121,7 @@ class SerialSimLink(LinkBase):
|
||||
rst_meth = rst_meth_map[self._rst_pin[1:]]
|
||||
rst_val = rst_val_map[self._rst_pin[0]]
|
||||
except:
|
||||
raise ValueError('Invalid reset pin %s' % self._rst_pin);
|
||||
raise ValueError('Invalid reset pin %s' % self._rst_pin)
|
||||
|
||||
rst_meth(rst_val)
|
||||
time.sleep(0.1) # 100 ms
|
||||
@@ -128,7 +132,7 @@ class SerialSimLink(LinkBase):
|
||||
if not b:
|
||||
return 0
|
||||
if ord(b) != 0x3b:
|
||||
return -1;
|
||||
return -1
|
||||
self._dbg_print("TS: 0x%x Direct convention" % ord(b))
|
||||
|
||||
while ord(b) == 0x3b:
|
||||
@@ -222,7 +226,7 @@ class SerialSimLink(LinkBase):
|
||||
if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?)
|
||||
continue
|
||||
if not b:
|
||||
break;
|
||||
break
|
||||
data += b
|
||||
|
||||
# Split datafield from SW
|
||||
|
||||
@@ -135,6 +135,23 @@ EF_UST_map = {
|
||||
109: 'MCPTT',
|
||||
110: 'ePDG configuration Information for Emergency Service support',
|
||||
111: 'ePDG configuration Information for Emergency Service configured',
|
||||
112: 'eCall Data over IMS',
|
||||
113: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [12]',
|
||||
114: 'From Preferred',
|
||||
115: 'IMS configuration data',
|
||||
116: 'TV configuration',
|
||||
117: '3GPP PS Data Off',
|
||||
118: '3GPP PS Data Off Service List',
|
||||
119: 'V2X',
|
||||
120: 'XCAP Configuration Data',
|
||||
121: 'EARFCN list for MTC/NB-IOT UEs',
|
||||
122: '5GS Mobility Management Information',
|
||||
123: '5G Security Parameters',
|
||||
124: 'Subscription identifier privacy support',
|
||||
125: 'SUCI calculation by the USIM',
|
||||
126: 'UAC Access Identities support',
|
||||
127: 'Expect control plane-based Steering of Roaming information during initial registration in VPLMN',
|
||||
128: 'Call control on PDU Session by USIM',
|
||||
}
|
||||
|
||||
LOCI_STATUS_map = {
|
||||
@@ -143,6 +160,7 @@ LOCI_STATUS_map = {
|
||||
2: 'plmn not allowed',
|
||||
3: 'locatation area not allowed'
|
||||
}
|
||||
|
||||
EF_USIM_ADF_map = {
|
||||
'LI': '6F05',
|
||||
'ARR': '6F06',
|
||||
|
||||
@@ -42,5 +42,28 @@ EF_IST_map = {
|
||||
16: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [31]',
|
||||
17: 'From Preferred',
|
||||
18: 'IMS configuration data',
|
||||
19: 'XCAP Configuration Data'
|
||||
19: 'XCAP Configuration Data',
|
||||
20: 'WebRTC URI',
|
||||
}
|
||||
|
||||
EF_ISIM_ADF_map = {
|
||||
'IST': '6F07',
|
||||
'IMPI': '6F02',
|
||||
'DOMAIN': '6F03',
|
||||
'IMPU': '6F04',
|
||||
'AD': '6FAD',
|
||||
'ARR': '6F06',
|
||||
'PCSCF': '6F09',
|
||||
'GBAP': '6FD5',
|
||||
'GBANL': '6FD7',
|
||||
'NAFKCA': '6FDD',
|
||||
'UICCIARI': '6FE7',
|
||||
'SMS': '6F3C',
|
||||
'SMSS': '6F43',
|
||||
'SMSR': '6F47',
|
||||
'SMSP': '6F42',
|
||||
'FromPreferred': '6FF7',
|
||||
'IMSConfigData': '6FF8',
|
||||
'XCAPConfigData': '6FFC',
|
||||
'WebRTCURI': '6FFA'
|
||||
}
|
||||
|
||||
@@ -313,4 +313,14 @@ EF_SST_map = {
|
||||
57: 'Multimedia Messaging Service (MMS)',
|
||||
58: 'Extension 8',
|
||||
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',
|
||||
}
|
||||
|
||||
275
pySim/utils.py
275
pySim/utils.py
@@ -122,11 +122,8 @@ def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
|
||||
if oplmn_disp: byte1 = byte1|0x02
|
||||
return i2h([byte1])+s2h(name)
|
||||
|
||||
def hexstr_to_fivebytearr(s):
|
||||
return [s[i:i+10] for i in range(0, len(s), 10) ]
|
||||
|
||||
def hexstr_to_threebytearr(s):
|
||||
return [s[i:i+6] for i in range(0, len(s), 6) ]
|
||||
def hexstr_to_Nbytearr(s, nbytes):
|
||||
return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ]
|
||||
|
||||
# Accepts hex string representing three bytes
|
||||
def dec_mcc_from_plmn(plmn):
|
||||
@@ -140,9 +137,9 @@ def dec_mcc_from_plmn(plmn):
|
||||
|
||||
def dec_mnc_from_plmn(plmn):
|
||||
ia = h2i(plmn)
|
||||
digit1 = ia[2] & 0x0F # 3rd byte, LSB
|
||||
digit2 = (ia[2] & 0xF0) >> 4 # 3rd byte, MSB
|
||||
digit3 = (ia[1] & 0xF0) >> 4 # 2nd byte, MSB
|
||||
digit1 = (ia[1] & 0xF0) >>4 # 2nd byte, MSB
|
||||
digit2 = ia[2] & 0x0F # 3rd byte, LSB
|
||||
digit3 = (ia[2] & 0xF0) >> 4 # 3nd byte, MSB
|
||||
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
|
||||
return 0xFFF # 4095
|
||||
return derive_mnc(digit1, digit2, digit3)
|
||||
@@ -177,7 +174,7 @@ def dec_xplmn_w_act(fivehexbytes):
|
||||
|
||||
def format_xplmn_w_act(hexstr):
|
||||
s = ""
|
||||
for rec_data in hexstr_to_fivebytearr(hexstr):
|
||||
for rec_data in hexstr_to_Nbytearr(hexstr, 5):
|
||||
rec_info = dec_xplmn_w_act(rec_data)
|
||||
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
||||
rec_str = "unused"
|
||||
@@ -226,7 +223,7 @@ def dec_xplmn(threehexbytes):
|
||||
|
||||
def format_xplmn(hexstr):
|
||||
s = ""
|
||||
for rec_data in hexstr_to_threebytearr(hexstr):
|
||||
for rec_data in hexstr_to_Nbytearr(hexstr, 3):
|
||||
rec_info = dec_xplmn(rec_data)
|
||||
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
||||
rec_str = "unused"
|
||||
@@ -252,7 +249,7 @@ def calculate_luhn(cc):
|
||||
"""
|
||||
Calculate Luhn checksum used in e.g. ICCID and IMEI
|
||||
"""
|
||||
num = map(int, str(cc))
|
||||
num = list(map(int, str(cc)))
|
||||
check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
|
||||
return 0 if check_digit == 10 else check_digit
|
||||
|
||||
@@ -460,19 +457,62 @@ def TLV_parser(bytelist):
|
||||
bytelist = bytelist[ L+2 : ]
|
||||
return ret
|
||||
|
||||
def dec_epdgid(hexstr):
|
||||
def enc_st(st, service, state=1):
|
||||
"""
|
||||
Decode ePDG Id to get EF.ePDGId or EF.ePDGIdEm.
|
||||
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
|
||||
Encodes the EF S/U/IST/EST and returns the updated Service Table
|
||||
|
||||
Parameters:
|
||||
st - Current value of SIM/USIM/ISIM Service Table
|
||||
service - Service Number to encode as activated/de-activated
|
||||
state - 1 mean activate, 0 means de-activate
|
||||
|
||||
Returns:
|
||||
s - Modified value of SIM/USIM/ISIM Service Table
|
||||
|
||||
Default values:
|
||||
- state: 1 - Sets the particular Service bit to 1
|
||||
"""
|
||||
st_bytes = [st[i:i+2] for i in range(0, len(st), 2) ]
|
||||
|
||||
s = ""
|
||||
# Check whether the requested service is present in each byte
|
||||
for i in range(0, len(st_bytes)):
|
||||
# Byte i contains info about Services num (8i+1) to num (8i+8)
|
||||
if service in range((8*i) + 1, (8*i) + 9):
|
||||
byte = int(st_bytes[i], 16)
|
||||
# Services in each byte are in order MSB to LSB
|
||||
# MSB - Service (8i+8)
|
||||
# LSB - Service (8i+1)
|
||||
mod_byte = 0x00
|
||||
# Copy bit by bit contents of byte to mod_byte with modified bit
|
||||
# for requested service
|
||||
for j in range(1, 9):
|
||||
mod_byte = mod_byte >> 1
|
||||
if service == (8*i) + j:
|
||||
mod_byte = state == 1 and mod_byte|0x80 or mod_byte&0x7f
|
||||
else:
|
||||
mod_byte = byte&0x01 == 0x01 and mod_byte|0x80 or mod_byte&0x7f
|
||||
byte = byte >> 1
|
||||
|
||||
s += ('%02x' % (mod_byte))
|
||||
else:
|
||||
s += st_bytes[i]
|
||||
|
||||
return s
|
||||
|
||||
def dec_addr_tlv(hexstr):
|
||||
"""
|
||||
Decode hex string to get EF.P-CSCF Address or EF.ePDGId or EF.ePDGIdEm.
|
||||
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104.
|
||||
"""
|
||||
|
||||
# Convert from hex str to int bytes list
|
||||
epdgid_bytes = h2i(hexstr)
|
||||
addr_tlv_bytes = h2i(hexstr)
|
||||
|
||||
s = ""
|
||||
|
||||
# Get list of tuples containing parsed TLVs
|
||||
tlvs = TLV_parser(epdgid_bytes)
|
||||
tlvs = TLV_parser(addr_tlv_bytes)
|
||||
|
||||
for tlv in tlvs:
|
||||
# tlv = (T, L, [V])
|
||||
@@ -490,29 +530,45 @@ def dec_epdgid(hexstr):
|
||||
|
||||
# First byte in the value has the address type
|
||||
addr_type = tlv[2][0]
|
||||
# TODO: Support parsing of IPv4 and IPv6
|
||||
# TODO: Support parsing of IPv6
|
||||
# Address Type: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), other (Reserved)
|
||||
if addr_type == 0x00: #FQDN
|
||||
# Skip address tye byte i.e. first byte in value list
|
||||
content = tlv[2][1:]
|
||||
s += "\t%s # %s\n" % (i2h(content), i2s(content))
|
||||
elif addr_type == 0x01: #IPv4
|
||||
# Skip address tye byte i.e. first byte in value list
|
||||
# Skip the unused byte in Octect 4 after address type byte as per 3GPP TS 31.102
|
||||
ipv4 = tlv[2][2:]
|
||||
content = '.'.join(str(x) for x in ipv4)
|
||||
s += "\t%s # %s\n" % (i2h(ipv4), content)
|
||||
|
||||
return s
|
||||
|
||||
def enc_epdgid(epdg_addr, addr_type='00'):
|
||||
def enc_addr_tlv(addr, addr_type='00'):
|
||||
"""
|
||||
Encode ePDG Id so it can be stored to EF.ePDGId or EF.ePDGIdEm.
|
||||
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
|
||||
Encode address TLV object used in EF.P-CSCF Address, EF.ePDGId and EF.ePDGIdEm.
|
||||
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104.
|
||||
|
||||
Default values:
|
||||
- addr_type: 00 - FQDN format of ePDG Address
|
||||
- addr_type: 00 - FQDN format of Address
|
||||
"""
|
||||
|
||||
s = ""
|
||||
|
||||
# TODO: Encoding of IPv4 and IPv6 address
|
||||
if addr_type == '00':
|
||||
hex_str = s2h(epdg_addr)
|
||||
# TODO: Encoding of IPv6 address
|
||||
if addr_type == '00': #FQDN
|
||||
hex_str = s2h(addr)
|
||||
s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str
|
||||
elif addr_type == '01': #IPv4
|
||||
ipv4_list = addr.split('.')
|
||||
ipv4_str = ""
|
||||
for i in ipv4_list:
|
||||
ipv4_str += ('%02x' % (int(i)))
|
||||
|
||||
# Unused bytes shall be set to 'ff'. i.e 4th Octet after Address Type is not used
|
||||
# IPv4 Address is in octet 5 to octet 8 of the TLV data object
|
||||
s += '80' + ('%02x' % ((len(ipv4_str)//2)+2)) + '01' + 'ff' + ipv4_str
|
||||
|
||||
return s
|
||||
|
||||
@@ -551,21 +607,158 @@ def init_reader(opts):
|
||||
"""
|
||||
Init card reader driver
|
||||
"""
|
||||
if opts.pcsc_dev is not None:
|
||||
print("Using PC/SC reader interface")
|
||||
from pySim.transport.pcsc import PcscSimLink
|
||||
sl = PcscSimLink(opts.pcsc_dev)
|
||||
elif opts.osmocon_sock is not None:
|
||||
print("Using Calypso-based (OsmocomBB) reader interface")
|
||||
from pySim.transport.calypso import CalypsoSimLink
|
||||
sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
|
||||
elif opts.modem_dev is not None:
|
||||
print("Using modem for Generic SIM Access (3GPP TS 27.007)")
|
||||
from pySim.transport.modem_atcmd import ModemATCommandLink
|
||||
sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud)
|
||||
else: # Serial reader is default
|
||||
print("Using serial reader interface")
|
||||
from pySim.transport.serial import SerialSimLink
|
||||
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
|
||||
try:
|
||||
if opts.pcsc_dev is not None:
|
||||
print("Using PC/SC reader interface")
|
||||
from pySim.transport.pcsc import PcscSimLink
|
||||
sl = PcscSimLink(opts.pcsc_dev)
|
||||
elif opts.osmocon_sock is not None:
|
||||
print("Using Calypso-based (OsmocomBB) reader interface")
|
||||
from pySim.transport.calypso import CalypsoSimLink
|
||||
sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
|
||||
elif opts.modem_dev is not None:
|
||||
print("Using modem for Generic SIM Access (3GPP TS 27.007)")
|
||||
from pySim.transport.modem_atcmd import ModemATCommandLink
|
||||
sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud)
|
||||
else: # Serial reader is default
|
||||
print("Using serial reader interface")
|
||||
from pySim.transport.serial import SerialSimLink
|
||||
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
|
||||
return sl
|
||||
except Exception as e:
|
||||
print("Card reader initialization failed with exception:\n" + str(e))
|
||||
return None
|
||||
|
||||
return sl
|
||||
|
||||
def enc_ePDGSelection(hexstr, mcc, mnc, epdg_priority='0001', epdg_fqdn_format='00'):
|
||||
"""
|
||||
Encode ePDGSelection so it can be stored at EF.ePDGSelection or EF.ePDGSelectionEm.
|
||||
See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
|
||||
|
||||
Default values:
|
||||
- epdg_priority: '0001' - 1st Priority
|
||||
- epdg_fqdn_format: '00' - Operator Identifier FQDN
|
||||
"""
|
||||
|
||||
plmn1 = enc_plmn(mcc, mnc) + epdg_priority + epdg_fqdn_format
|
||||
# TODO: Handle encoding of Length field for length more than 127 Bytes
|
||||
content = '80' + ('%02x' % (len(plmn1)//2)) + plmn1
|
||||
content = rpad(content, len(hexstr))
|
||||
return content
|
||||
|
||||
def dec_ePDGSelection(sixhexbytes):
|
||||
"""
|
||||
Decode ePDGSelection to get EF.ePDGSelection or EF.ePDGSelectionEm.
|
||||
See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
|
||||
"""
|
||||
|
||||
res = {'mcc': 0, 'mnc': 0, 'epdg_priority': 0, 'epdg_fqdn_format': ''}
|
||||
plmn_chars = 6
|
||||
epdg_priority_chars = 4
|
||||
epdg_fqdn_format_chars = 2
|
||||
# first three bytes (six ascii hex chars)
|
||||
plmn_str = sixhexbytes[:plmn_chars]
|
||||
# two bytes after first three bytes
|
||||
epdg_priority_str = sixhexbytes[plmn_chars:plmn_chars + epdg_priority_chars]
|
||||
# one byte after first five bytes
|
||||
epdg_fqdn_format_str = sixhexbytes[plmn_chars + epdg_priority_chars:plmn_chars + epdg_priority_chars + epdg_fqdn_format_chars]
|
||||
res['mcc'] = dec_mcc_from_plmn(plmn_str)
|
||||
res['mnc'] = dec_mnc_from_plmn(plmn_str)
|
||||
res['epdg_priority'] = epdg_priority_str
|
||||
res['epdg_fqdn_format'] = epdg_fqdn_format_str == '00' and 'Operator Identifier FQDN' or 'Location based FQDN'
|
||||
return res
|
||||
|
||||
def format_ePDGSelection(hexstr):
|
||||
ePDGSelection_info_tag_chars = 2
|
||||
ePDGSelection_info_tag_str = hexstr[:2]
|
||||
s = ""
|
||||
# Minimum length
|
||||
len_chars = 2
|
||||
# TODO: Need to determine length properly - definite length support only
|
||||
# Inconsistency in spec: 3GPP TS 31.102 version 15.2.0 Release 15, 4.2.104
|
||||
# As per spec, length is 5n, n - number of PLMNs
|
||||
# But, each PLMN entry is made of PLMN (3 Bytes) + ePDG Priority (2 Bytes) + ePDG FQDN format (1 Byte)
|
||||
# Totalling to 6 Bytes, maybe length should be 6n
|
||||
len_str = hexstr[ePDGSelection_info_tag_chars:ePDGSelection_info_tag_chars+len_chars]
|
||||
|
||||
# Not programmed scenario
|
||||
if int(len_str, 16) == 255 or int(ePDGSelection_info_tag_str, 16) == 255:
|
||||
len_chars = 0
|
||||
ePDGSelection_info_tag_chars = 0
|
||||
if len_str[0] == '8':
|
||||
# The bits 7 to 1 denotes the number of length octets if length > 127
|
||||
if int(len_str[1]) > 0:
|
||||
# Update number of length octets
|
||||
len_chars = len_chars * int(len_str[1])
|
||||
len_str = hexstr[ePDGSelection_info_tag_chars:len_chars]
|
||||
|
||||
content_str = hexstr[ePDGSelection_info_tag_chars+len_chars:]
|
||||
# Right pad to prevent index out of range - multiple of 6 bytes
|
||||
content_str = rpad(content_str, len(content_str) + (12 - (len(content_str) % 12)))
|
||||
for rec_data in hexstr_to_Nbytearr(content_str, 6):
|
||||
rec_info = dec_ePDGSelection(rec_data)
|
||||
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
||||
rec_str = "unused"
|
||||
else:
|
||||
rec_str = "MCC: %03d MNC: %03d ePDG Priority: %s ePDG FQDN format: %s" % \
|
||||
(rec_info['mcc'], rec_info['mnc'], rec_info['epdg_priority'], rec_info['epdg_fqdn_format'])
|
||||
s += "\t%s # %s\n" % (rec_data, rec_str)
|
||||
return s
|
||||
|
||||
def get_addr_type(addr):
|
||||
"""
|
||||
Validates the given address and returns it's type (FQDN or IPv4 or IPv6)
|
||||
Return: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), None (Bad address argument given)
|
||||
|
||||
TODO: Handle IPv6
|
||||
"""
|
||||
|
||||
# Empty address string
|
||||
if not len(addr):
|
||||
return None
|
||||
|
||||
import sys
|
||||
# Handle python3 and python2 - unicode
|
||||
if sys.version_info[0] < 3:
|
||||
addr_str = unicode(addr)
|
||||
else:
|
||||
addr_str = addr
|
||||
|
||||
addr_list = addr.split('.')
|
||||
|
||||
# Check for IPv4/IPv6
|
||||
try:
|
||||
import ipaddress
|
||||
# Throws ValueError if addr is not correct
|
||||
ipa = ipaddress.ip_address(addr_str)
|
||||
|
||||
if ipa.version == 4:
|
||||
return 0x01
|
||||
elif ipa.version == 6:
|
||||
return 0x02
|
||||
except Exception as e:
|
||||
invalid_ipv4 = True
|
||||
for i in addr_list:
|
||||
# Invalid IPv4 may qualify for a valid FQDN, so make check here
|
||||
# e.g. 172.24.15.300
|
||||
import re
|
||||
if not re.match('^[0-9_]+$', i):
|
||||
invalid_ipv4 = False
|
||||
break
|
||||
|
||||
if invalid_ipv4:
|
||||
return None
|
||||
|
||||
fqdn_flag = True
|
||||
for i in addr_list:
|
||||
# Only Alpha-numeric characters and hyphen - RFC 1035
|
||||
import re
|
||||
if not re.match("^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)?$", i):
|
||||
fqdn_flag = False
|
||||
break
|
||||
|
||||
# FQDN
|
||||
if fqdn_flag:
|
||||
return 0x00
|
||||
|
||||
return None
|
||||
|
||||
@@ -12,7 +12,7 @@ class DecTestCase(unittest.TestCase):
|
||||
"ffffff0002",
|
||||
"ffffff0001",
|
||||
]
|
||||
self.assertEqual(utils.hexstr_to_fivebytearr(input_str), expected)
|
||||
self.assertEqual(utils.hexstr_to_Nbytearr(input_str, 5), expected)
|
||||
|
||||
def testDecMCCfromPLMN(self):
|
||||
self.assertEqual(utils.dec_mcc_from_plmn("92f501"), 295)
|
||||
|
||||
@@ -42,7 +42,9 @@ HPLMNAcT:
|
||||
|
||||
ACC: 0008
|
||||
MSISDN: Not available
|
||||
AD: 00000002
|
||||
Administrative data: 00000002
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: disabled
|
||||
SIM Service Table: ff3cc3ff030fff0f000fff03f0c0
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
@@ -114,6 +116,5 @@ USIM Service Table: 01ea1ffc21360480010000
|
||||
Service 64 - VGCS security
|
||||
Service 65 - VBS security
|
||||
|
||||
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
|
||||
Done !
|
||||
|
||||
|
||||
@@ -49,7 +49,9 @@ OPLMNwAcT:
|
||||
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 6a82.
|
||||
ACC: abce
|
||||
MSISDN: Not available
|
||||
AD: 00ffff02
|
||||
Administrative data: 00ffff02
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: enabled
|
||||
SIM Service Table: ff33ff0f3c00ff0f000cf0c0f0030000
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
@@ -130,6 +132,5 @@ USIM Service Table: 9eff1b3c37fe5900000000
|
||||
Service 53 - Extension 8
|
||||
Service 55 - MMS User Connectivity Parameters
|
||||
|
||||
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
|
||||
Done !
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||
ACC: ffff
|
||||
MSISDN: Not available
|
||||
AD: 000000
|
||||
Administrative data: 000000
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: disabled
|
||||
SIM Service Table: ff3fff0f0300f003000c
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
|
||||
@@ -4,4 +4,4 @@ ICCID=1122334455667788990
|
||||
KI=AABBCCDDEEFFAABBCCDDEEFFAABBCCDD
|
||||
OPC=12345678901234567890123456789012
|
||||
IMSI=001010000000102
|
||||
ADM=72273953
|
||||
ADM=11111111
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Using PC/SC reader interface
|
||||
Reading ...
|
||||
Autodetected card type: sysmoISIM-SJA2
|
||||
ICCID: 8988211900000000004
|
||||
ICCID: 8988211900000000025
|
||||
IMSI: 001010000000102
|
||||
GID1: ffffffffffffffffffff
|
||||
GID2: ffffffffffffffffffff
|
||||
@@ -52,9 +52,11 @@ HPLMNAcT:
|
||||
ffffff0000 # unused
|
||||
ffffff0000 # unused
|
||||
|
||||
ACC: 0001
|
||||
MSISDN (NPI=1 ToN=1): +1234
|
||||
AD: 00000002
|
||||
ACC: 0200
|
||||
MSISDN (NPI=1 ToN=3): 6766266
|
||||
Administrative data: 00000002
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: disabled
|
||||
SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
@@ -101,12 +103,12 @@ SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
|
||||
Service 59 - MMS User Connectivity Parameters
|
||||
|
||||
EHPLMN:
|
||||
00f110 # MCC: 001 MNC: 001
|
||||
ffffff # unused
|
||||
ffffff # unused
|
||||
ffffff # unused
|
||||
00f110 # MCC: 001 MNC: 001
|
||||
ffffff # unused
|
||||
ffffff # unused
|
||||
ffffff # unused
|
||||
|
||||
USIM Service Table: beff9f9de73e0408400170730000002e00000000
|
||||
USIM Service Table: beff9f9de73e0408400170330006002e00000000
|
||||
Service 2 - Fixed Dialling Numbers (FDN)
|
||||
Service 3 - Extension 2
|
||||
Service 4 - Service Dialling Numbers (SDN)
|
||||
@@ -154,11 +156,54 @@ USIM Service Table: beff9f9de73e0408400170730000002e00000000
|
||||
Service 90 - Operator CSG Lists and corresponding indications
|
||||
Service 93 - Communication Control for IMS by USIM
|
||||
Service 94 - Extended Terminal Applications
|
||||
Service 95 - Support of UICC access to IMS
|
||||
Service 106 - ePDG configuration Information support
|
||||
Service 107 - ePDG configuration Information configured
|
||||
Service 122 - 5GS Mobility Management Information
|
||||
Service 123 - 5G Security Parameters
|
||||
Service 124 - Subscription identifier privacy support
|
||||
Service 126 - UAC Access Identities support
|
||||
|
||||
ePDGId:
|
||||
Not available
|
||||
|
||||
ePDGSelection:
|
||||
ffffffffffff # unused
|
||||
ffffffffffff # unused
|
||||
ffffffffffff # unused
|
||||
ffffffffffff # unused
|
||||
|
||||
P-CSCF:
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
|
||||
Home Network Domain Name: Not available
|
||||
IMS private user identity: Not available
|
||||
IMS public user identity:
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
|
||||
UICC IARI:
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
Not available
|
||||
|
||||
ISIM Service Table: 190200
|
||||
Service 1 - P-CSCF address
|
||||
Service 4 - GBA-based Local Key Establishment Mechanism
|
||||
|
||||
@@ -54,7 +54,9 @@ HPLMNAcT:
|
||||
|
||||
ACC: 0008
|
||||
MSISDN (NPI=1 ToN=1): +77776336143
|
||||
AD: 00000002
|
||||
Administrative data: 00000002
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: disabled
|
||||
SIM Service Table: ff3fffff3f003f1ff00c00c0f00000
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
@@ -138,6 +140,5 @@ USIM Service Table: 9e6b1dfc67f6580000
|
||||
Service 53 - Extension 8
|
||||
Service 55 - MMS User Connectivity Parameters
|
||||
|
||||
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
|
||||
Done !
|
||||
|
||||
|
||||
@@ -16,7 +16,9 @@ OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||
ACC: 0008
|
||||
MSISDN: Not available
|
||||
AD: 000000
|
||||
Administrative data: 000000
|
||||
MS operation mode: normal operation
|
||||
Ciphering Indicator: disabled
|
||||
SIM Service Table: ff3fff0f0f0000030000
|
||||
Service 1 - CHV1 disable function
|
||||
Service 2 - Abbreviated Dialling Numbers (ADN)
|
||||
|
||||
Reference in New Issue
Block a user