dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37615?usp=email )
Change subject: pySim-shell: clean up method calls in do_switch_channel
......................................................................
pySim-shell: clean up method calls in do_switch_channel
The function do_switch_channel method calls methods in RuntimeLchan
that should be private. There is also a code duplication in
RuntimeLchan that should be cleaned up.
Related: OS#6092
Change-Id: Ie5e5f45787abaaf032e1b49f51d447653cf2c996
---
M pySim-shell.py
M pySim/runtime.py
2 files changed, 29 insertions(+), 14 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/15/37615/1
diff --git a/pySim-shell.py b/pySim-shell.py
index e99c365..8f654bd 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -859,9 +859,9 @@
@cmd2.with_argparser(switch_chan_parser)
def do_switch_channel(self, opts):
"""Switch currently active logical channel."""
- self._cmd.lchan._select_pre(self._cmd)
+ self._cmd.lchan.unregister_cmds(self._cmd)
self._cmd.lchan = self._cmd.rs.lchan[opts.chan_nr]
- self._cmd.lchan._select_post(self._cmd)
+ self._cmd.lchan.register_cmds(self._cmd)
self._cmd.update_prompt()
def do_status(self, opts):
diff --git a/pySim/runtime.py b/pySim/runtime.py
index db1641f..71bf8d9 100644
--- a/pySim/runtime.py
+++ b/pySim/runtime.py
@@ -262,7 +262,8 @@
raise ValueError(
"Cannot select unknown file by name %s, only hexadecimal 4 digit FID is allowed" % fid)
- self._select_pre(cmd_app)
+ # unregister commands of old file
+ self.unregister_cmds(cmd_app)
try:
# We access the card through the select_file method of the scc object.
@@ -295,12 +296,6 @@
self._select_post(cmd_app, f, data)
- def _select_pre(self, cmd_app):
- # unregister commands of old file
- if cmd_app and self.selected_file.shell_commands:
- for c in self.selected_file.shell_commands:
- cmd_app.unregister_command_set(c)
-
def _select_post(self, cmd_app, file:Optional[CardFile] = None, select_resp_data = None):
# we store some reference data (see above) about the currently selected file.
# This data must be updated after every select.
@@ -316,9 +311,7 @@
self.selected_file_fcp = None
# register commands of new file
- if cmd_app and self.selected_file.shell_commands:
- for c in self.selected_file.shell_commands:
- cmd_app.register_command_set(c)
+ self.register_cmds(cmd_app)
def select_file(self, file: CardFile, cmd_app=None):
"""Select a file (EF, DF, ADF, MF, ...).
@@ -331,7 +324,9 @@
inter_path = self.selected_file.build_select_path_to(file)
if not inter_path:
raise RuntimeError('Cannot determine path from %s to %s' % (self.selected_file, file))
- self._select_pre(cmd_app)
+
+ # unregister commands of old file
+ self.unregister_cmds(cmd_app)
# be sure the variables that we pass to _select_post contain valid values.
selected_file = self.selected_file
@@ -577,8 +572,14 @@
raise TypeError("Only works with BER-TLV EF")
return self.scc.set_data(self.selected_file.fid, tag, data_hex, conserve=self.rs.conserve_write)
+ def register_cmds(self, cmd_app=None):
+ """Register command set that is associated with the currently selected file"""
+ if cmd_app and self.selected_file.shell_commands:
+ for c in self.selected_file.shell_commands:
+ cmd_app.register_command_set(c)
+
def unregister_cmds(self, cmd_app=None):
- """Unregister all file specific commands."""
+ """Unregister command set that is associated with the currently seleted file"""
if cmd_app and self.selected_file.shell_commands:
for c in self.selected_file.shell_commands:
cmd_app.unregister_command_set(c)
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37615?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Ie5e5f45787abaaf032e1b49f51d447653cf2c996
Gerrit-Change-Number: 37615
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37612?usp=email )
Change subject: pySim-shell: move export code into filesystem class model
......................................................................
pySim-shell: move export code into filesystem class model
The code that generates the filesystem export lines for the various
different file structures can be moved into the filesystem class model.
This simplifies the code since we do not need any extra logic to
distinguish between the different file structures.
Related: OS#6092
Change-Id: Icc2ee60cfc4379411744ca1033d79a1ee9cff5a6
---
M pySim-shell.py
M pySim/filesystem.py
2 files changed, 118 insertions(+), 58 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/12/37612/1
diff --git a/pySim-shell.py b/pySim-shell.py
index 0e7e63c..4f5959b 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -599,66 +599,14 @@
self._cmd.poutput("# directory: %s (%s)" % (df_path, df_path_fid))
try:
fcp_dec = self._cmd.lchan.select(filename, self._cmd)
- self._cmd.poutput("# file: %s (%s)" % (
- self._cmd.lchan.selected_file.name, self._cmd.lchan.selected_file.fid))
-
- structure = self._cmd.lchan.selected_file_structure()
- self._cmd.poutput("# structure: %s" % str(structure))
+ self._cmd.poutput("# file: %s (%s)" %
+ (self._cmd.lchan.selected_file.name, self._cmd.lchan.selected_file.fid))
+ self._cmd.poutput("# structure: %s" % self._cmd.lchan.selected_file_structure())
self._cmd.poutput("# RAW FCP Template: %s" % str(self._cmd.lchan.selected_file_fcp_hex))
self._cmd.poutput("# Decoded FCP Template: %s" % str(self._cmd.lchan.selected_file_fcp))
+ self._cmd.poutput("select " + self._cmd.lchan.selected_file.fully_qualified_path_str())
+ self._cmd.poutput(self._cmd.lchan.selected_file.export(as_json, self._cmd.lchan))
- for f in df_path_list:
- self._cmd.poutput("select " + str(f))
- self._cmd.poutput("select " + self._cmd.lchan.selected_file.name)
-
- if structure == 'transparent':
- if as_json:
- result = self._cmd.lchan.read_binary_dec()
- self._cmd.poutput("update_binary_decoded '%s'" % json.dumps(result[0], cls=JsonEncoder))
- else:
- result = self._cmd.lchan.read_binary()
- self._cmd.poutput("update_binary " + str(result[0]))
- elif structure == 'cyclic' or structure == 'linear_fixed':
- # Use number of records specified in select response
- num_of_rec = self._cmd.lchan.selected_file_num_of_rec()
- if num_of_rec:
- for r in range(1, num_of_rec + 1):
- if as_json:
- result = self._cmd.lchan.read_record_dec(r)
- self._cmd.poutput("update_record_decoded %d '%s'" % (r, json.dumps(result[0], cls=JsonEncoder)))
- else:
- result = self._cmd.lchan.read_record(r)
- self._cmd.poutput("update_record %d %s" % (r, str(result[0])))
-
- # When the select response does not return the number of records, read until we hit the
- # first record that cannot be read.
- else:
- r = 1
- while True:
- try:
- if as_json:
- result = self._cmd.lchan.read_record_dec(r)
- self._cmd.poutput("update_record_decoded %d '%s'" % (r, json.dumps(result[0], cls=JsonEncoder)))
- else:
- result = self._cmd.lchan.read_record(r)
- self._cmd.poutput("update_record %d %s" % (r, str(result[0])))
- except SwMatchError as e:
- # We are past the last valid record - stop
- if e.sw_actual == "9402":
- break
- # Some other problem occurred
- else:
- raise e
- r = r + 1
- elif structure == 'ber_tlv':
- tags = self._cmd.lchan.retrieve_tags()
- for t in tags:
- result = self._cmd.lchan.retrieve_data(t)
- (tag, l, val, remainer) = bertlv_parse_one(h2b(result[0]))
- self._cmd.poutput("set_data 0x%02x %s" % (t, b2h(val)))
- else:
- raise RuntimeError(
- 'Unsupported structure "%s" of file "%s"' % (structure, filename))
except Exception as e:
bad_file_str = df_path + "/" + str(filename) + ", " + str(e)
self._cmd.poutput("# bad file: %s" % bad_file_str)
diff --git a/pySim/filesystem.py b/pySim/filesystem.py
index 77482cc..ad124ff 100644
--- a/pySim/filesystem.py
+++ b/pySim/filesystem.py
@@ -35,7 +35,9 @@
from cmd2 import CommandSet, with_default_category
from smartcard.util import toBytes
-from pySim.utils import sw_match, h2b, b2h, is_hex, auto_int, auto_uint8, auto_uint16, is_hexstr
+from pySim.utils import sw_match, h2b, b2h, is_hex, auto_int, auto_uint8, auto_uint16, is_hexstr, JsonEncoder
+from pySim.utils import bertlv_parse_one
+
from pySim.construct import filter_dict, parse_construct, build_construct
from pySim.jsonpath import js_path_modify
from pySim.commands import SimCardCommands
@@ -774,6 +776,25 @@
raise NotImplementedError(
"%s encoder not yet implemented. Patches welcome." % self)
+ @staticmethod
+ def export(as_json: bool, lchan):
+ """
+ Export the file contents of a TransparentEF. This method returns a shell command string (See also ShellCommand
+ definition in this class) that can be used to write the file contents back.
+ """
+
+ if lchan.selected_file_structure() != 'transparent':
+ raise ValueError("selected file has structure type '%s', expecting a file with structure 'transparent'" %
+ lchan.selected_file_structure())
+ export_str = ""
+ if as_json:
+ result = lchan.read_binary_dec()
+ export_str += ("update_binary_decoded '%s'\n" % json.dumps(result[0], cls=JsonEncoder))
+ else:
+ result = lchan.read_binary()
+ export_str += ("update_binary %s\n" % str(result[0]))
+ return export_str.strip()
+
class LinFixedEF(CardEF):
"""Linear Fixed EF (Entry File) in the smart card filesystem.
@@ -1044,6 +1065,54 @@
raise NotImplementedError(
"%s encoder not yet implemented. Patches welcome." % self)
+ @staticmethod
+ def export(as_json: bool, lchan):
+ """
+ Export the file contents of a LinFixedEF (or a CyclicEF). This method returns a shell command string (See also
+ ShellCommand definition in this class) that can be used to write the file contents back.
+ """
+
+ # A CyclicEF is a subclass of LinFixedEF.
+ if lchan.selected_file_structure() != 'linear_fixed' and lchan.selected_file_structure() != 'cyclic':
+ raise ValueError("selected file has structure type '%s', expecting a file with structure 'linear_fixed' or 'cyclic'" %
+ lchan.selected_file_structure())
+
+ export_str = ""
+
+ # Use number of records specified in select response
+ num_of_rec = lchan.selected_file_num_of_rec()
+ if num_of_rec:
+ for r in range(1, num_of_rec + 1):
+ if as_json:
+ result = lchan.read_record_dec(r)
+ export_str += ("update_record_decoded %d '%s'\n" % (r, json.dumps(result[0], cls=JsonEncoder)))
+ else:
+ result = lchan.read_record(r)
+ export_str += ("update_record %d %s\n" % (r, str(result[0])))
+
+ # In case the select response does not return the number of records, read until we hit the first record that
+ # cannot be read.
+ else:
+ r = 1
+ while True:
+ try:
+ if as_json:
+ result = lchan.read_record_dec(r)
+ export_str += ("update_record_decoded %d '%s'\n" % (r, json.dumps(result[0], cls=JsonEncoder)))
+ else:
+ result = lchan.read_record(r)
+ export_str += ("update_record %d %s\n" % (r, str(result[0])))
+ except SwMatchError as e:
+ # We are past the last valid record - stop
+ if e.sw_actual == "9402":
+ break
+ # Some other problem occurred
+ else:
+ raise e
+ r = r + 1
+
+ return export_str.strip()
+
class CyclicEF(LinFixedEF):
"""Cyclic EF (Entry File) in the smart card filesystem"""
@@ -1264,6 +1333,33 @@
self.size = size
self.shell_commands = [self.ShellCommands()]
+ @staticmethod
+ def export(as_json: bool, lchan):
+ """
+ Export the file contents of a BerTlvEF. This method returns a shell command string (See also ShellCommand
+ definition in this class) that can be used to write the file contents back.
+ """
+
+ if lchan.selected_file_structure() != 'ber_tlv':
+ raise ValueError("selected file has structure type '%s', expecting a file with structure 'ber_tlv'" %
+ lchan.selected_file_structure())
+
+ # TODO: Add JSON output as soon as we have a set_data_decoded command and a retrieve_data_dec method.
+ if as_json:
+ raise NotImplementedError("BerTlvEF encoder not yet implemented. Patches welcome.")
+
+ export_str = ""
+ tags = lchan.retrieve_tags()
+ if tags == []:
+ export_str += "# empty file, no tags"
+ else:
+ for t in tags:
+ result = lchan.retrieve_data(t)
+ (tag, l, val, remainer) = bertlv_parse_one(h2b(result[0]))
+ export_str += ("set_data 0x%02x %s\n" % (t, b2h(val)))
+ return export_str.strip()
+
+
def interpret_sw(sw_data: dict, sw: str):
"""Interpret a given status word.
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37612?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: Icc2ee60cfc4379411744ca1033d79a1ee9cff5a6
Gerrit-Change-Number: 37612
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37613?usp=email )
Change subject: pySim-shell: turn "ADF-escape-code" into an lchan method.
......................................................................
pySim-shell: turn "ADF-escape-code" into an lchan method.
When we traverse the file system using the command "export" we will
also select all ADFs but not all ADFs may have UICC file system support.
This makes it impossible to exit those ADFs again. To exit anyway we
select an application with filesystem support first and then the parent
EF we wanted to select originally. This method may not only be useful
when traversing the filesystem, so let's put it into the RuntimeLchan
class and change it a little so that it would also work if the ADF in
question is an a sub DF.
Related: OS#6092
Change-Id: I72de51bc7519fafbcc71d829719a8af35d774342
---
M pySim-shell.py
M pySim/runtime.py
2 files changed, 50 insertions(+), 26 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/13/37613/1
diff --git a/pySim-shell.py b/pySim-shell.py
index 4f5959b..2eb37ea 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -535,32 +535,7 @@
# below, so we must not move up.
if skip_df == False:
self.walk(indent + 1, action_ef, action_df, context, **kwargs)
-
- parent = self._cmd.lchan.selected_file.parent
- df = self._cmd.lchan.selected_file
- adf = self._cmd.lchan.selected_adf
- if isinstance(parent, CardMF) and (adf and adf.has_fs == False):
- # Not every application that may be present on a GlobalPlatform card will support the SELECT
- # command as we know it from ETSI TS 102 221, section 11.1.1. In fact the only subset of
- # SELECT we may rely on is the OPEN SELECT command as specified in GlobalPlatform Card
- # Specification, section 11.9. Unfortunately the OPEN SELECT command only supports the
- # "select by name" method, which means we can only select an application and not a file.
- # The consequence of this is that we may get trapped in an application that does not have
- # ISIM/USIM like file system support and the only way to leave that application is to select
- # an ISIM/USIM application in order to get the file system access back.
- #
- # To automate this escape-route while traversing the file system we will check whether
- # the parent file is the MF. When this is the case and the selected ADF has no file system
- # support, we will select an arbitrary ADF that has file system support first and from there
- # we will then select the MF.
- for selectable in parent.get_selectables().items():
- if isinstance(selectable[1], CardADF) and selectable[1].has_fs == True:
- self._cmd.lchan.select(selectable[1].name, self._cmd)
- break
- self._cmd.lchan.select(df.get_mf().name, self._cmd)
- else:
- # Normal DF/ADF selection
- fcp_dec = self._cmd.lchan.select("..", self._cmd)
+ self._cmd.lchan.select_parent(self._cmd)
elif action_ef:
df_before_action = self._cmd.lchan.selected_file
diff --git a/pySim/runtime.py b/pySim/runtime.py
index a56d884..a56df4d 100644
--- a/pySim/runtime.py
+++ b/pySim/runtime.py
@@ -396,6 +396,36 @@
return self.selected_file_fcp
+ def select_parent(self, cmd_app=None):
+ """Select the parent file of the currently selected file. This method also works in case the currently selected
+ file is an ADF without UICC file system support and can be used to exit those ADFs.
+ """
+ parent = self.selected_file.parent
+ df = self.selected_file
+ adf = self.selected_adf
+ if adf and adf.has_fs == False:
+ # Not every application that may be present on a GlobalPlatform card will support the SELECT
+ # command as we know it from ETSI TS 102 221, section 11.1.1. In fact the only subset of
+ # SELECT we may rely on is the OPEN SELECT command as specified in GlobalPlatform Card
+ # Specification, section 11.9. Unfortunately the OPEN SELECT command only supports the
+ # "select by name" method, which means we can only select an application and not a file.
+ # The consequence of this is that we may get trapped in an application that does not have
+ # ISIM/USIM like file system support and the only way to leave that application is to select
+ # an ISIM/USIM application in order to get the file system access back.
+ #
+ # To automate this escape-route while traversing the file system we will check whether
+ # the parent file is the MF. When this is the case and the selected ADF has no file system
+ # support, we will select an arbitrary ADF that has file system support first and from there
+ # we will then select the MF.
+ for selectable in parent.get_selectables().items():
+ if isinstance(selectable[1], CardADF) and selectable[1].has_fs == True:
+ self.select(selectable[1].name, cmd_app)
+ break
+ self.select_file(parent, cmd_app)
+
+ # Select the parent file normally
+ self.select_file(parent, cmd_app)
+
def status(self):
"""Request STATUS (current selected file FCP) from card."""
(data, _sw) = self.scc.status()
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37613?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I72de51bc7519fafbcc71d829719a8af35d774342
Gerrit-Change-Number: 37613
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
dexter has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/37611?usp=email )
Change subject: pySim-shell: fix comment formatting
......................................................................
pySim-shell: fix comment formatting
Related: OS#6092
Change-Id: I101868a6f0220b62977c5e633df2607467cfba91
---
M pySim-shell.py
1 file changed, 12 insertions(+), 3 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/11/37611/1
diff --git a/pySim-shell.py b/pySim-shell.py
index 7523ca2..0e7e63c 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -734,9 +734,8 @@
@cmd2.with_argparser(verify_adm_parser)
def do_verify_adm(self, opts):
"""Verify the ADM (Administrator) PIN specified as argument. This is typically needed in order
-to get write/update permissions to most of the files on SIM cards.
-
-Currently only ADM1 is supported."""
+ to get write/update permissions to most of the files on SIM cards. Currently only ADM1 is supported.
+ """
if opts.ADM1:
# use specified ADM-PIN
pin_adm = sanitize_pin_adm(opts.ADM1)
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/37611?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I101868a6f0220b62977c5e633df2607467cfba91
Gerrit-Change-Number: 37611
Gerrit-PatchSet: 1
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newchange
Attention is currently required from: laforge, lynxis lazus.
dexter has posted comments on this change. ( https://gerrit.osmocom.org/c/pysim/+/36127?usp=email )
Change subject: Revert "tlv: Fix from_dict() symmetry"
......................................................................
Patch Set 1: Code-Review+1
(1 comment)
Patchset:
PS1:
I have tried this and I can confirm that this fixes the problem with the ARA-M interface.
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/36127?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I1710bf9124acf7952d3231b104407e9ac998d6a8
Gerrit-Change-Number: 36127
Gerrit-PatchSet: 1
Gerrit-Owner: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: lynxis lazus <lynxis(a)fe80.eu>
Gerrit-Comment-Date: Thu, 25 Jul 2024 14:58:47 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment
dexter has submitted this change. ( https://gerrit.osmocom.org/c/osmo-pcu/+/37550?usp=email )
Change subject: fix E1 TS output when used with osmo-e1d
......................................................................
fix E1 TS output when used with osmo-e1d
The original code did E1 raw TS output by posting directly to
&ts->raw.tx_queue instead of calling e1inp_ts_send_raw();
doing so bypasses the call to driver->want_write performed in
e1inp layer. This approach worked for DAHDI where no
select-for-write is used; however, e1inp interface to osmo-e1d
does use select-for-write, hence applications like osmo-mgw
do need to use e1inp_ts_send_raw() API in order to work
correctly.
Change-Id: Ia2e0fa27195fc1ae75e441038eb4adeb4cf1d6cf
---
M src/ericsson-rbs/er_ccu_if.c
1 file changed, 19 insertions(+), 1 deletion(-)
Approvals:
pespin: Looks good to me, but someone else must approve
Jenkins Builder: Verified
laforge: Looks good to me, approved
falconia: Looks good to me, but someone else must approve
diff --git a/src/ericsson-rbs/er_ccu_if.c b/src/ericsson-rbs/er_ccu_if.c
index 98abbf7..ad7f353 100644
--- a/src/ericsson-rbs/er_ccu_if.c
+++ b/src/ericsson-rbs/er_ccu_if.c
@@ -126,7 +126,7 @@
DEBUG_BYTES_MAX ? DEBUG_BYTES_MAX : msgb_length(msg)));
/* Hand data over to the E1 stack */
- msgb_enqueue(&ts->raw.tx_queue, msg);
+ e1inp_ts_send_raw(ts, msg);
}
/* Callback function to handle incoming E1 traffic */
--
To view, visit https://gerrit.osmocom.org/c/osmo-pcu/+/37550?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-pcu
Gerrit-Branch: master
Gerrit-Change-Id: Ia2e0fa27195fc1ae75e441038eb4adeb4cf1d6cf
Gerrit-Change-Number: 37550
Gerrit-PatchSet: 2
Gerrit-Owner: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: falconia <falcon(a)freecalypso.org>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-MessageType: merged