Attention is currently required from: dexter, laforge.
Hello Jenkins Builder, dexter, fixeria,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/pysim/+/35440?usp=email
to look at the new patch set (#3).
The following approvals got outdated and were removed:
Verified+1 by Jenkins Builder
Change subject: Fix enumeration of GlobbalPlatformISDR during card_init()
......................................................................
Fix enumeration of GlobbalPlatformISDR during card_init()
We used __subclasses__(), but this only returns the immediate
subclasses and not all further/nested subclasses. Instead, we must
use the pySim.utils.all_subclasses() function to really get all of them.
The hack to use the method signature of the constructor to determine if
it's an intermediate class didn't work, as even GlobbalPlatformISDR
has a optional argument for non-default AIDs. So let's introduce an
explicit class attribute for that purpose.
Change-Id: I7fb1637f8f7a149b536c4d77dac92736c526aa6c
---
M pySim/app.py
M pySim/global_platform.py
2 files changed, 22 insertions(+), 4 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/40/35440/3
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/35440?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: I7fb1637f8f7a149b536c4d77dac92736c526aa6c
Gerrit-Change-Number: 35440
Gerrit-PatchSet: 3
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: dexter <pmaier(a)sysmocom.de>
Gerrit-MessageType: newpatchset
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/35452?usp=email )
Change subject: Implement convoluted encoding of UCS-2 as per TS 102 221 Annex A
......................................................................
Implement convoluted encoding of UCS-2 as per TS 102 221 Annex A
TS 102 221 Annex A defines three variants of encoding UCS-2 characters
into byte streams in files on UICC cards: One rather simplistic one, and
two variants for optimizing memory utilization on the card.
Let's impelement a construct "Ucs2Adapter" class for this.
Change-Id: Ic8bc8f71079faec1bf0e538dc0dfa21403869c6d
---
M pySim/construct.py
M tests/test_construct.py
2 files changed, 216 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/52/35452/1
diff --git a/pySim/construct.py b/pySim/construct.py
index b6e19a0..661b010 100644
--- a/pySim/construct.py
+++ b/pySim/construct.py
@@ -48,6 +48,163 @@
def _encode(self, obj, context, path):
return codecs.encode(obj, "utf-8")
+class Ucs2Adapter(Adapter):
+ """convert a bytes() type that contains UCS2 encoded characters encoded as defined in TS 102 221
+ Annex A to normal python string representation (and back)."""
+ def _decode(self, obj, context, path):
+ # In case the string contains only 0xff bytes we interpret it as an empty string
+ if obj == b'\xff' * len(obj):
+ return ""
+ if obj[0] == 0x80:
+ # TS 102 221 Annex A Variant 1
+ return codecs.decode(obj[1:], 'utf_16_be')
+ elif obj[0] == 0x81:
+ # TS 102 221 Annex A Variant 2
+ out = ""
+ # second byte contains a value indicating the number of characters
+ num_of_chars = obj[1]
+ # the third byte contains an 8 bit number which defines bits 15 to 8 of a 16 bit base
+ # pointer, where bit 16 is set to zero, and bits 7 to 1 are also set to zero. These
+ # sixteen bits constitute a base pointer to a "half-page" in the UCS2 code space
+ base_ptr = obj[2] << 7
+ for ch in obj[3:3+num_of_chars]:
+ # if bit 8 of the byte is set to zero, the remaining 7 bits of the byte contain a
+ # GSM Default Alphabet character, whereas if bit 8 of the byte is set to one, then
+ # the remaining seven bits are an offset value added to the 16 bit base pointer
+ # defined earlier, and the resultant 16 bit value is a UCS2 code point
+ if ch & 0x80:
+ codepoint = (ch & 0x7f) + base_ptr
+ print("codepoint=0x%x" % codepoint)
+ out += codecs.decode(codepoint.to_bytes(2), 'utf_16_be')
+ else:
+ out += codecs.decode(ch.to_bytes(1), 'gsm03.38')
+ return out
+ elif obj[0] == 0x82:
+ # TS 102 221 Annex A Variant 3
+ out = ""
+ # second byte contains a value indicating the number of characters
+ num_of_chars = obj[1]
+ # third and fourth bytes contain a 16 bit number which defines the complete 16 bit base
+ # pointer to a half-page in the UCS2 code space, for use with some or all of the
+ # remaining bytes in the string
+ base_ptr = obj[2] << 8 | obj[3]
+ for ch in obj[4:4+num_of_chars]:
+ # if bit 8 of the byte is set to zero, the remaining 7 bits of the byte contain a
+ # GSM Default Alphabet character, whereas if bit 8 of the byte is set to one, the
+ # remaining seven bits are an offset value added to the base pointer defined in
+ # bytes three and four, and the resultant 16 bit value is a UCS2 code point, else: #
+ # GSM default alphabet
+ if ch & 0x80:
+ codepoint = (ch & 0x7f) + base_ptr
+ out += codecs.decode(codepoint.to_bytes(2), 'utf_16_be')
+ else:
+ out += codecs.decode(ch.to_bytes(1), 'gsm03.38')
+ return out
+
+ def _encode(self, obj, context, path):
+ def encodable_in_gsm338(instr: str) -> bool:
+ """Determine if given input string is encode-ale in gsm03.38."""
+ try:
+ # TODO: figure out if/how we can constrain to default alphabet. The gsm0338
+ # library seems to include the spanish lock/shift table
+ codecs.encode(instr, 'gsm03.38')
+ except ValueError:
+ return False
+ return True
+
+ def codepoints_not_in_gsm338(instr: str) -> typing.List[int]:
+ """Return an integer list of UCS2 codepoints for all characters of 'inster'
+ which are not representable in the GSM 03.38 default alphabet."""
+ codepoint_list = []
+ for c in instr:
+ if encodable_in_gsm338(c):
+ continue
+ c_codepoint = int.from_bytes(codecs.encode(c, 'utf_16_be'))
+ codepoint_list.append(c_codepoint)
+ return codepoint_list
+
+ def diff_between_min_and_max_of_list(inlst: typing.List) -> int:
+ return max(inlst) - min(inlst)
+
+ def encodable_in_variant2(instr: str) -> bool:
+ codepoint_prefix = None
+ for c in instr:
+ if encodable_in_gsm338(c):
+ continue
+ c_codepoint = int.from_bytes(codecs.encode(c, 'utf_16_be'))
+ if c_codepoint >= 0x8000:
+ return False
+ c_prefix = c_codepoint >> 7
+ if codepoint_prefix is None:
+ codepoint_prefix = c_prefix
+ else:
+ if c_prefix != codepoint_prefix:
+ return False
+ return True
+
+ def encodable_in_variant3(instr: str) -> bool:
+ codepoint_list = codepoints_not_in_gsm338(instr)
+ # compute delta between max and min; check if it's encodable in 7 bits
+ if diff_between_min_and_max_of_list(codepoint_list) >= 0x80:
+ return False
+ return True
+
+ def _encode_variant1(instr: str) -> bytes:
+ """Encode according to TS 102 221 Annex A Variant 1"""
+ return b'\x80' + codecs.encode(obj, 'utf_16_be')
+
+ def _encode_variant2(instr: str) -> bytes:
+ """Encode according to TS 102 221 Annex A Variant 2"""
+ codepoint_prefix = None
+ # second byte contains a value indicating the number of characters
+ hdr = b'\x81' + len(instr).to_bytes(1)
+ chars = b''
+ for c in instr:
+ try:
+ enc = codecs.encode(c, 'gsm03.38')
+ except ValueError:
+ c_codepoint = int.from_bytes(codecs.encode(c, 'utf_16_be'))
+ c_prefix = c_codepoint >> 7
+ if codepoint_prefix is None:
+ codepoint_prefix = c_prefix
+ assert codepoint_prefix == c_prefix
+ enc = (0x80 + (c_codepoint & 0x7f)).to_bytes(1)
+ chars += enc
+ if codepoint_prefix == None:
+ codepoint_prefix = 0
+ return hdr + codepoint_prefix.to_bytes(1) + chars
+
+ def _encode_variant3(instr: str) -> bytes:
+ """Encode according to TS 102 221 Annex A Variant 3"""
+ # second byte contains a value indicating the number of characters
+ hdr = b'\x82' + len(instr).to_bytes(1)
+ chars = b''
+ codepoint_list = codepoints_not_in_gsm338(instr)
+ codepoint_base = min(codepoint_list)
+ for c in instr:
+ try:
+ # if bit 8 of the byte is set to zero, the remaining 7 bits of the byte contain a GSM
+ # Default # Alphabet character
+ enc = codecs.encode(c, 'gsm03.38')
+ except ValueError:
+ # if bit 8 of the byte is set to one, the remaining seven bits are an offset
+ # value added to the base pointer defined in bytes three and four, and the
+ # resultant 16 bit value is a UCS2 code point
+ c_codepoint = int.from_bytes(codecs.encode(c, 'utf_16_be'))
+ c_codepoint_delta = c_codepoint - codepoint_base
+ assert c_codepoint_delta < 0x80
+ enc = (0x80 + c_codepoint_delta).to_bytes(1)
+ chars += enc
+ # third and fourth bytes contain a 16 bit number which defines the complete 16 bit base
+ # pointer to a half-page in the UCS2 code space
+ return hdr + codepoint_base.to_bytes(2) + chars
+
+ if encodable_in_variant2(obj):
+ return _encode_variant2(obj)
+ elif encodable_in_variant3(obj):
+ return _encode_variant3(obj)
+ else:
+ return _encode_variant1(obj)
class BcdAdapter(Adapter):
"""convert a bytes() type to a string of BCD nibbles."""
diff --git a/tests/test_construct.py b/tests/test_construct.py
index f1bee5a..11822a8 100644
--- a/tests/test_construct.py
+++ b/tests/test_construct.py
@@ -33,5 +33,49 @@
self.assertEqual(filter_dict(inp), out)
+class TestUcs2Adapter(unittest.TestCase):
+ # the three examples from TS 102 221 Annex A
+ EXAMPLE1 = b'\x80\x00\x30\x00\x31\x00\x32\x00\x33'
+ EXAMPLE2 = b'\x81\x05\x13\x53\x95\xa6\xa6\xff\xff'
+ EXAMPLE3 = b'\x82\x05\x05\x30\x2d\x82\xd3\x2d\x31'
+ ad = Ucs2Adapter(GreedyBytes)
+
+ def test_example1_decode(self):
+ dec = self.ad._decode(self.EXAMPLE1, None, None)
+ self.assertEqual(dec, "0123")
+
+ def test_example2_decode(self):
+ dec = self.ad._decode(self.EXAMPLE2, None, None)
+ self.assertEqual(dec, "S\u0995\u09a6\u09a6\u09ff")
+
+ def test_example3_decode(self):
+ dec = self.ad._decode(self.EXAMPLE3, None, None)
+ self.assertEqual(dec, "-\u0532\u0583-1")
+
+ testdata = [
+ # variant 2 with only GSM alphabet characters
+ ( "mahlzeit", '8108006d61686c7a656974' ),
+ # variant 2 with mixed GSM alphabet + UCS2
+ ( "mahlzeit\u099523", '810b136d61686c7a656974953233' ),
+ # variant 3 due to codepoint exceeding 8 bit
+ ( "mahl\u8023zeit", '820980236d61686c807a656974' ),
+ # variant 1 as there is no common codepoint pointer / prefix
+ ( "\u3000\u2000\u1000", '80300020001000' ),
+ ]
+
+ def test_data_decode(self):
+ for string, encoded_hex in self.testdata:
+ encoded = h2b(encoded_hex)
+ dec = self.ad._decode(encoded, None, None)
+ self.assertEqual(dec, string)
+
+ def test_data_encode(self):
+ for string, encoded_hex in self.testdata:
+ encoded = h2b(encoded_hex)
+ re_enc = self.ad._encode(string, None, None)
+ self.assertEqual(encoded, re_enc)
+
+
+
if __name__ == "__main__":
unittest.main()
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/35452?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: Ic8bc8f71079faec1bf0e538dc0dfa21403869c6d
Gerrit-Change-Number: 35452
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newchange
laforge has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/35453?usp=email )
Change subject: support UCS-2 characters in EF.MMSUP, EF.ADN, EF.SPN, EF.PNN, EF.ECC
......................................................................
support UCS-2 characters in EF.MMSUP, EF.ADN, EF.SPN, EF.PNN, EF.ECC
Now that we have support for the UCS-2 encoding as per TS 102 221 Annex A,
we can start to make use of it from various file constructs.
As some specs say "Either 7-bit GSM or UCS-2" we also introduce
a related automatic GsmOrUcs2Adapter and GsmOrUcs2String class.
Change-Id: I4eb8aea0a13260a143e2c60fca73c3c4312fd3b2
---
M pySim/construct.py
M pySim/ts_31_102.py
M pySim/ts_51_011.py
3 files changed, 56 insertions(+), 4 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/53/35453/1
diff --git a/pySim/construct.py b/pySim/construct.py
index 661b010..4189dda 100644
--- a/pySim/construct.py
+++ b/pySim/construct.py
@@ -48,6 +48,29 @@
def _encode(self, obj, context, path):
return codecs.encode(obj, "utf-8")
+class GsmOrUcs2Adapter(Adapter):
+ """Try to encode into a GSM 03.38 string; if that fails, fall back to UCS-2 as described
+ in TS 102 221 Annex A."""
+ def _decode(self, obj, context, path):
+ # In case the string contains only 0xff bytes we interpret it as an empty string
+ if obj == b'\xff' * len(obj):
+ return ""
+ # one of the magic bytes of TS 102 221 Annex A
+ if obj[0] in [0x80, 0x81, 0x82]:
+ ad = Ucs2Adapter(GreedyBytes)
+ else:
+ ad = GsmString(GreedyBytes)
+ return ad._decode(obj, context, path)
+
+ def _encode(self, obj, context, path):
+ # first try GSM 03.38; then fall back to TS 102 221 Annex A UCS-2
+ try:
+ ad = GsmString(GreedyBytes)
+ return ad._encode(obj, context, path)
+ except:
+ ad = Ucs2Adapter(GreedyBytes)
+ return ad._encode(obj, context, path)
+
class Ucs2Adapter(Adapter):
"""convert a bytes() type that contains UCS2 encoded characters encoded as defined in TS 102 221
Annex A to normal python string representation (and back)."""
@@ -447,6 +470,20 @@
'''
return GsmStringAdapter(Rpad(Bytes(n), pattern=b'\xff'), codec='gsm03.38')
+def GsmOrUcs2String(n):
+ '''
+ GSM 03.38 or UCS-2 (TS 102 221 Annex A) encoded byte string of fixed length n.
+ Encoder appends padding bytes (b'\\xff') to maintain
+ length. Decoder removes those trailing bytes.
+
+ Exceptions are raised for invalid characters
+ and length excess.
+
+ Parameters:
+ n (Integer): Fixed length of the encoded byte string
+ '''
+ return GsmOrUcs2Adapter(Rpad(Bytes(n), pattern=b'\xff'))
+
class GreedyInteger(Construct):
"""A variable-length integer implementation, think of combining GrredyBytes with BytesInteger."""
def __init__(self, signed=False, swapped=False, minlen=0):
diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py
index 16526c2..1a35cb7 100644
--- a/pySim/ts_31_102.py
+++ b/pySim/ts_31_102.py
@@ -529,7 +529,7 @@
cc_construct = BcdAdapter(Rpad(Bytes(3)))
category_construct = FlagsEnum(Byte, police=1, ambulance=2, fire_brigade=3, marine_guard=4,
mountain_rescue=5, manual_ecall=6, automatic_ecall=7)
- alpha_construct = GsmStringAdapter(Rpad(GreedyBytes))
+ alpha_construct = GsmOrUcs2Adapter(Rpad(GreedyBytes))
def __init__(self, fid='6fb7', sfid=0x01, name='EF.ECC',
desc='Emergency Call Codes'):
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 422b35e..6523769 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -145,7 +145,7 @@
def __init__(self, fid='6f3a', sfid=None, name='EF.ADN', desc='Abbreviated Dialing Numbers', ext=1, **kwargs):
super().__init__(fid, sfid=sfid, name=name, desc=desc, rec_len=(14, 30), **kwargs)
ext_name = 'ext%u_record_id' % ext
- self._construct = Struct('alpha_id'/COptional(GsmStringAdapter(Rpad(Bytes(this._.total_len-14)), codec='ascii')),
+ self._construct = Struct('alpha_id'/COptional(GsmOrUcs2Adapter(Rpad(Bytes(this._.total_len-14)))),
'len_of_bcd'/Int8ub,
'ton_npi'/TonNpi,
'dialing_nr'/ExtendedBcdAdapter(BcdAdapter(Rpad(Bytes(10)))),
@@ -514,7 +514,7 @@
'hide_in_oplmn'/Flag,
'show_in_hplmn'/Flag,
# Bytes 2..17
- 'spn'/Bytewise(GsmString(16))
+ 'spn'/Bytewise(GsmOrUcs2String(16))
)
# TS 51.011 Section 10.3.13
@@ -929,7 +929,7 @@
# TS 51.011 Section 10.3.54
class EF_MMSUP(LinFixedEF):
class MMS_UserPref_ProfileName(BER_TLV_IE, tag=0x81):
- pass
+ _construct = GsmOrUcs2Adapter(GreedyBytes)
class MMS_UserPref_Info(BER_TLV_IE, tag=0x82):
pass
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/35453?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: I4eb8aea0a13260a143e2c60fca73c3c4312fd3b2
Gerrit-Change-Number: 35453
Gerrit-PatchSet: 1
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: newchange
keith has submitted this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email )
Change subject: VTY: fix config indentation for pcu-socket params
......................................................................
VTY: fix config indentation for pcu-socket params
osmo-bsc would not start with a config written from the vty due
to incorrect identation on the pcu-socket parameters.
Change-Id: I36a66794e654989b4b8bf54bb3727ccbfc2131fa
---
M src/osmo-bsc/bsc_vty.c
1 file changed, 14 insertions(+), 2 deletions(-)
Approvals:
Jenkins Builder: Verified
fixeria: Looks good to me, but someone else must approve
keith: Looks good to me, approved
diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c
index 73c5cc2..925f21f 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -415,9 +415,9 @@
}
if (gsmnet->pcu_sock_path)
- vty_out(vty, " pcu-socket %s%s", gsmnet->pcu_sock_path, VTY_NEWLINE);
+ vty_out(vty, " pcu-socket %s%s", gsmnet->pcu_sock_path, VTY_NEWLINE);
if (gsmnet->pcu_sock_wqueue_len_max != BSC_PCU_SOCK_WQUEUE_LEN_DEFAULT)
- vty_out(vty, " pcu-socket-wqueue-length %u%s", gsmnet->pcu_sock_wqueue_len_max,
+ vty_out(vty, " pcu-socket-wqueue-length %u%s", gsmnet->pcu_sock_wqueue_len_max,
VTY_NEWLINE);
neighbor_ident_vty_write_network(vty, " ");
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I36a66794e654989b4b8bf54bb3727ccbfc2131fa
Gerrit-Change-Number: 35443
Gerrit-PatchSet: 4
Gerrit-Owner: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-MessageType: merged
Attention is currently required from: fixeria, laforge.
keith has posted comments on this change. ( https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email )
Change subject: VTY: fix config indentation for pcu-socket params
......................................................................
Patch Set 3: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I36a66794e654989b4b8bf54bb3727ccbfc2131fa
Gerrit-Change-Number: 35443
Gerrit-PatchSet: 3
Gerrit-Owner: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Comment-Date: Wed, 27 Dec 2023 17:26:23 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment
Attention is currently required from: keith, laforge.
Hello Jenkins Builder, laforge,
I'd like you to reexamine a change. Please visit
https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email
to look at the new patch set (#3).
The following approvals got outdated and were removed:
Code-Review+1 by laforge, Code-Review+2 by keith, Verified+1 by Jenkins Builder
The change is no longer submittable: Code-Review and Verified are unsatisfied now.
Change subject: VTY: fix config indentation for pcu-socket params
......................................................................
VTY: fix config indentation for pcu-socket params
osmo-bsc would not start with a config written from the vty due
to incorrect identation on the pcu-socket parameters.
Change-Id: I36a66794e654989b4b8bf54bb3727ccbfc2131fa
---
M src/osmo-bsc/bsc_vty.c
1 file changed, 14 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/43/35443/3
--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/35443?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I36a66794e654989b4b8bf54bb3727ccbfc2131fa
Gerrit-Change-Number: 35443
Gerrit-PatchSet: 3
Gerrit-Owner: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: keith <keith(a)rhizomatica.org>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-CC: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Attention: laforge <laforge(a)osmocom.org>
Gerrit-Attention: keith <keith(a)rhizomatica.org>
Gerrit-MessageType: newpatchset