neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/43864?usp=email )
Change subject: personalization: EnumParam: implement as value_map, not enum.IntEnum
......................................................................
personalization: EnumParam: implement as value_map, not enum.IntEnum
Because of (1) and (2) below, using enum.IntEnum is not a good choice
for EnumParam. Use a plain dict as value map.
EnumParam's idea is to be a mapping
human-readable-value-for-UI -> PES-value
and with enum.IntEnum we...
(1) ...we impose python namespace rules onto
human-readable-value-for-UI: "My Value" is not allowed, only "my_value".
By using enum.IntEnum, we make it impossible to use human readable
values like:
- "SUCI-on" (dash not allowed in python identifier)
- "True" (python keyword not allowed)
- "2" (numeric constant cannot be a python identifier)
(2) ...we limit PES-values to int. The mapping should support any type
that the given PES attribute needs (int, bool, bytes, ...).
Future: upcoming ConfigurableParameters depend on this patch:
- MncLen (labels "2" and "3")
- EuiccMandatoryServiceParam (values True and False)
- EfUstServiceParam like SuciInUsim (labels "SUCI-in-UE" and
"SUCI-in-USIM")
History: this is near the first version of EnumParam, before it was
modified by fixeria to use enum.IntEnum, as requested by CR. I realize
now that enum.IntEnum will not work for upcoming eSIM parameters.
Change-Id: I690ceccf0ec7ef7067bcaa5cec1303cdaf0f78a4
Jenkins: skip-card-test
---
M pySim/esim/saip/personalization.py
M tests/unittests/test_configurable_parameters.py
M tests/unittests/xo/test_configurable_parameters
3 files changed, 109 insertions(+), 118 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/64/43864/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index a136aa8..e9ed709 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -420,68 +420,70 @@
class EnumParam(ConfigurableParameter):
- """ConfigurableParameter for named integer enumeration values.
+ """ConfigurableParameter for named value enumerations.
- Subclasses must define a nested enum.IntEnum named 'Values' listing all valid names and their
- integer codes. apply_val() and get_values_from_pes() are not implemented here and this must
- be inherited from another mixin."""
-
- class Values(enum.IntEnum):
- pass # subclasses override this
+ Subclasses define an own value_map, and implement their own apply_val() and get_values_from_pes().
+ """
+ value_map = {
+ # For example:
+ #'Meaningful label for value 23': 0x23,
+ # Where 0x23 is a valid value to use for apply_val(), of any valid type.
+ }
+ _value_map_reverse = None
@classmethod
- def validate_val(cls, val) -> int:
- if isinstance(val, int):
- try:
- return int(cls.Values(val))
- except ValueError:
- pass
- elif isinstance(val, str):
- member = cls.map_name_to_val(val, strict=False)
- if member is not None:
- return member
+ def validate_val(cls, val):
+ orig_val = val
+ enum_val = None
+ if isinstance(val, str):
+ enum_name = val
+ enum_val = cls.map_name_to_val(enum_name)
- valid = ', '.join(m.name for m in cls.Values)
- raise ValueError(f"{cls.get_name()}: invalid argument: {val!r}. Valid arguments are: {valid}")
+ # if the str is not one of the known value_map.keys(), is it maybe one of value_map.keys()?
+ if enum_val is None and val in cls.value_map.values():
+ enum_val = val
+
+ if enum_val not in cls.value_map.values():
+ raise ValueError(f"{cls.get_name()}: invalid argument: {orig_val!r}. Valid arguments are:"
+ f" {', '.join(cls.value_map.keys())}")
+
+ return enum_val
@classmethod
- def map_name_to_val(cls, name: str, strict=True) -> int:
- """Return the integer value for a given enum member name. Performs an exact match first,
- then falls back to fuzzy matching (case-insensitive, punctuation-insensitive)."""
- try:
- return int(cls.Values[name])
- except KeyError:
- pass
+ def map_name_to_val(cls, name:str, strict=True):
+ val = cls.value_map.get(name)
+ if val is not None:
+ return val
- clean = cls.clean_name_str(name)
- for member in cls.Values:
- if cls.clean_name_str(member.name) == clean:
- return int(member)
+ clean_name = cls.clean_name_str(name)
+ for k, v in cls.value_map.items():
+ if clean_name == cls.clean_name_str(k):
+ return v
if strict:
- valid = ', '.join(m.name for m in cls.Values)
- raise ValueError(f"{cls.get_name()}: {name!r} is not a known value. Known values are: {valid}")
+ raise ValueError(f"Problem in {cls.get_name()}: {name!r} is not a known value."
+ f" Known values are: {cls.value_map.keys()!r}")
return None
@classmethod
def map_val_to_name(cls, val, strict=False) -> str:
- """Return the enum member name for a given integer value."""
- try:
- return cls.Values(val).name
- except ValueError:
- if strict:
- raise ValueError(f"{cls.get_name()}: {val!r} ({type(val).__name__}) is not a known value.")
- return None
+ if cls._value_map_reverse is None:
+ cls._value_map_reverse = dict((v, k) for k, v in cls.value_map.items())
+
+ name = cls._value_map_reverse.get(val)
+ if name:
+ return name
+ if strict:
+ raise ValueError(f"Problem in {cls.get_name()}: {val!r} ({type(val)}) is not a known value."
+ f" Known values are: {cls.value_map.values()!r}")
+ return None
@classmethod
- def name_normalize(cls, name: str) -> str:
- """Map a (possibly fuzzy) name to its canonical enum member name."""
- return cls.Values(cls.map_name_to_val(name)).name
+ def name_normalize(cls, name:str) -> str:
+ return cls.map_val_to_name(cls.map_name_to_val(name))
@classmethod
- def clean_name_str(cls, val: str) -> str:
- """Strip punctuation and case for fuzzy name comparison.
- Treats hyphens and underscores as equivalent (both removed)."""
+ def clean_name_str(cls, val):
return re.sub('[^0-9A-Za-z]', '', val).lower()
@@ -664,69 +666,57 @@
class MncLen(EnumParam):
- """MNC length. Sets only the MNC length field in EF.AD (Administrative Data).
- Accepted values: integer 2 or 3, digit strings '2' or '3', or enum names 'MNC2'/'MNC3'.
- """
+ """MNC length. Must be either 2 or 3. Sets only the MNC length field in EF-AD (Administrative Data)."""
name = 'MNC-LEN'
- example_input = '2'
+ value_map = { '2': 2, '3': 3 }
default_source = param_source.ConstantSource
-
- class Values(enum.IntEnum):
- MNC2 = 2
- MNC3 = 3
+ example_input = '2'
@classmethod
- def validate_val(cls, val):
- if isinstance(val, str) and val.isdigit():
- val = int(val)
- return super().validate_val(val)
-
- @classmethod
- def _get_f_ad(cls, pe: ProfileElement):
- if not hasattr(pe, 'files'):
- return None
- f_ad = pe.files.get('ef-ad', None)
- if f_ad and f_ad.body:
- return f_ad
- return None
-
- @classmethod
- def _decode_f_ad(cls, f_ad):
- try:
- ef_ad_dec = EF_AD().decode_bin(f_ad.body)
- except StreamError:
- return None
- if 'mnc_len' not in ef_ad_dec:
- return None
- return ef_ad_dec
-
- @classmethod
- def apply_val(cls, pes: ProfileElementSequence, val: int):
+ def apply_val(cls, pes: ProfileElementSequence, val):
+ """val must be an int: either 2 or 3"""
for pe in pes.get_pes_for_type('usim'):
- f_ad = cls._get_f_ad(pe)
- if f_ad is None:
+ if not hasattr(pe, 'files'):
+ continue
+ f_ad = pe.files.get('ef-ad')
+ if not f_ad:
continue
# decode existing values
- ef_ad_dec = cls._decode_f_ad(f_ad)
- if ef_ad_dec is None:
+ if not f_ad.body:
+ continue
+ try:
+ ef_ad = EF_AD()
+ ef_ad_dec = ef_ad.decode_bin(f_ad.body)
+ except StreamError:
+ continue
+ if 'mnc_len' not in ef_ad_dec:
continue
# change mnc_len
ef_ad_dec['mnc_len'] = val
# re-encode into the File body
- f_ad.body = EF_AD().encode_bin(ef_ad_dec)
+ f_ad.body = ef_ad.encode_bin(ef_ad_dec)
pe.file2pe(f_ad)
@classmethod
def get_values_from_pes(cls, pes: ProfileElementSequence):
for pe in pes.get_pes_for_type('usim'):
- f_ad = cls._get_f_ad(pe)
+ if not hasattr(pe, 'files'):
+ continue
+ f_ad = pe.files.get('ef-ad', None)
if f_ad is None:
continue
- ef_ad_dec = cls._decode_f_ad(f_ad)
- if ef_ad_dec is None:
+
+ try:
+ ef_ad = EF_AD()
+ ef_ad_dec = ef_ad.decode_bin(f_ad.body)
+ except StreamError:
continue
- mnc_len = ef_ad_dec.get('mnc_len')
- yield { cls.name: str(mnc_len) }
+
+ mnc_len = ef_ad_dec.get('mnc_len', None)
+ if mnc_len is None:
+ continue
+
+ yield { cls.name: cls.map_val_to_name(int(mnc_len)) }
class SdKey(BinaryParam):
@@ -1100,17 +1090,17 @@
"""use validate_val() from EnumParam, and apply_val() from AlgoConfig.
In get_values_from_pes(), return enum value names, not raw values."""
name = "Algorithm"
+ # as in pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn
+ value_map = {
+ "Milenage" : 1,
+ "TUAK" : 2,
+ "usim-test" : 3,
+ }
algo_config_key = 'algorithmID'
example_input = "Milenage"
default_source = param_source.ConstantSource
- # as in pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn
- class Values(enum.IntEnum):
- Milenage = 1
- TUAK = 2
- usim_test = 3 # input 'usim-test' also accepted via fuzzy matching
-
- # EnumParam.validate_val() returns the int values from Values
+ # EnumParam.validate_val() returns the int values from value_map
@classmethod
def get_values_from_pes(cls, pes: ProfileElementSequence):
diff --git a/tests/unittests/test_configurable_parameters.py b/tests/unittests/test_configurable_parameters.py
index 47f9eb8..0115640 100755
--- a/tests/unittests/test_configurable_parameters.py
+++ b/tests/unittests/test_configurable_parameters.py
@@ -148,7 +148,7 @@
Paramtest(param_cls=p13n.AlgorithmID,
val='usim-test',
expect_clean_val=3,
- expect_val='usim_test'),
+ expect_val='usim-test'),
Paramtest(param_cls=p13n.AlgorithmID,
val=1,
@@ -161,7 +161,7 @@
Paramtest(param_cls=p13n.AlgorithmID,
val=3,
expect_clean_val=3,
- expect_val='usim_test'),
+ expect_val='usim-test'),
Paramtest(param_cls=p13n.K,
val='01020304050607080910111213141516',
@@ -559,7 +559,7 @@
def test_validate_by_name_exact(self):
self.assertEqual(p13n.AlgorithmID.validate_val('Milenage'), 1)
self.assertEqual(p13n.AlgorithmID.validate_val('TUAK'), 2)
- self.assertEqual(p13n.AlgorithmID.validate_val('usim_test'), 3)
+ self.assertEqual(p13n.AlgorithmID.validate_val('usim-test'), 3)
def test_validate_by_int(self):
self.assertEqual(p13n.AlgorithmID.validate_val(1), 1)
@@ -572,7 +572,6 @@
self.assertEqual(p13n.AlgorithmID.validate_val('tuak'), 2)
def test_validate_fuzzy_hyphen_underscore(self):
- # 'usim-test' has a hyphen; enum member is 'usim_test' — must fuzzy-match
self.assertEqual(p13n.AlgorithmID.validate_val('usim-test'), 3)
def test_validate_invalid_name(self):
@@ -609,7 +608,7 @@
def test_map_val_known(self):
self.assertEqual(p13n.AlgorithmID.map_val_to_name(1), 'Milenage')
self.assertEqual(p13n.AlgorithmID.map_val_to_name(2), 'TUAK')
- self.assertEqual(p13n.AlgorithmID.map_val_to_name(3), 'usim_test')
+ self.assertEqual(p13n.AlgorithmID.map_val_to_name(3), 'usim-test')
def test_map_val_unknown_nonstrict(self):
self.assertIsNone(p13n.AlgorithmID.map_val_to_name(99))
@@ -623,7 +622,9 @@
def test_name_normalize(self):
self.assertEqual(p13n.AlgorithmID.name_normalize('Milenage'), 'Milenage')
self.assertEqual(p13n.AlgorithmID.name_normalize('milenage'), 'Milenage')
- self.assertEqual(p13n.AlgorithmID.name_normalize('usim-test'), 'usim_test')
+ self.assertEqual(p13n.AlgorithmID.name_normalize('usimtest'), 'usim-test')
+ self.assertEqual(p13n.AlgorithmID.name_normalize('usim_test'), 'usim-test')
+ self.assertEqual(p13n.AlgorithmID.name_normalize('USIM Test'), 'usim-test')
# --- clean_name_str ---
diff --git a/tests/unittests/xo/test_configurable_parameters b/tests/unittests/xo/test_configurable_parameters
index 0946979..b2c9a5b 100644
--- a/tests/unittests/xo/test_configurable_parameters
+++ b/tests/unittests/xo/test_configurable_parameters
@@ -86,33 +86,33 @@
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val='Milenage':str)
clean_val=1:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'Milenage'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val='TUAK':str)
clean_val=2:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'TUAK'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val='usim-test':str)
clean_val=3:int
- previous value: ['usim_test']
- read_back_val={'Algorithm': 'usim_test'}:{str}
+ previous value: ['usim-test']
+ read_back_val={'Algorithm': 'usim-test'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val=1:int)
clean_val=1:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'Milenage'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val=2:int)
clean_val=2:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'TUAK'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der AlgorithmID(val=3:int)
clean_val=3:int
- previous value: ['usim_test']
- read_back_val={'Algorithm': 'usim_test'}:{str}
+ previous value: ['usim-test']
+ read_back_val={'Algorithm': 'usim-test'}:{str}
ok: TS48v5_SAIP2.1A_NoBERTLV.der K(val='01020304050607080910111213141516':str)
clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes
@@ -961,33 +961,33 @@
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val='Milenage':str)
clean_val=1:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'Milenage'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val='TUAK':str)
clean_val=2:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'TUAK'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val='usim-test':str)
clean_val=3:int
- previous value: ['usim_test']
- read_back_val={'Algorithm': 'usim_test'}:{str}
+ previous value: ['usim-test']
+ read_back_val={'Algorithm': 'usim-test'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val=1:int)
clean_val=1:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'Milenage'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val=2:int)
clean_val=2:int
- previous value: ['usim_test']
+ previous value: ['usim-test']
read_back_val={'Algorithm': 'TUAK'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der AlgorithmID(val=3:int)
clean_val=3:int
- previous value: ['usim_test']
- read_back_val={'Algorithm': 'usim_test'}:{str}
+ previous value: ['usim-test']
+ read_back_val={'Algorithm': 'usim-test'}:{str}
ok: TS48v5_SAIP2.3_BERTLV_SUCI.der K(val='01020304050607080910111213141516':str)
clean_val=b'\x01\x02\x03\x04\x05\x06\x07\x08\t\x10\x11\x12\x13\x14\x15\x16':bytes
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/43864?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I690ceccf0ec7ef7067bcaa5cec1303cdaf0f78a4
Gerrit-Change-Number: 43864
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
Attention is currently required from: fixeria, neels.
pespin has posted comments on this change by fixeria. ( https://gerrit.osmocom.org/c/osmo-bts/+/43863?usp=email )
Change subject: rsl: support Early IA with frequency hopping
......................................................................
Patch Set 1: Code-Review+1
--
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/43863?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: I632e46cccbf1151a88d2dfaf8cb42ce2647206a5
Gerrit-Change-Number: 43863
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-CC: Jenkins Builder
Gerrit-Attention: neels <nhofmeyr(a)sysmocom.de>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Comment-Date: Fri, 09 Oct 2026 20:49:10 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Attention is currently required from: fixeria.
pespin has posted comments on this change by fixeria. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43862?usp=email )
Change subject: bts: drop mp_l1_supports_gprs, run all GPRS tests
......................................................................
Patch Set 1:
(1 comment)
Patchset:
PS1:
May this still be needed to run tests using real C123 hardware? (OS#3155)
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43862?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: Ibe8db314c2eb676d536779d5875456d17ecb60e8
Gerrit-Change-Number: 43862
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-CC: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Comment-Date: Fri, 09 Oct 2026 20:45:22 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
fixeria has uploaded this change for review. ( https://gerrit.osmocom.org/c/osmo-bts/+/43863?usp=email )
Change subject: rsl: support Early IA with frequency hopping
......................................................................
rsl: support Early IA with frequency hopping
When osmo-bsc sends the RR Immediate Assignment before the target
lchan is active (early IA), osmo-bts holds it back until the lchan
is activated. The target TRX is currently found by the ARFCN in the
Channel Description, so this only works if hopping is disabled (H=0).
With hopping enabled (H=1), the Channel Description has MAIO/HSN
and no ARFCN, so the IMM ASS is sent to the MS right away.
For H=1, find the target TRX whose timeslot hops with the given
MAIO/HSN instead. If more than one TRX matches (different hopping
groups sharing the same MAIO/HSN on the same timeslot), don't hold
back the IMM ASS, the same as when no TRX matches.
This makes BTS_Tests.TC_early_immediate_assignment pass when run
in the frequency hopping configuration.
Change-Id: I632e46cccbf1151a88d2dfaf8cb42ce2647206a5
AI-Assisted: yes (Claude)
Related: SYS#5559
---
M src/common/rsl.c
1 file changed, 45 insertions(+), 19 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/osmo-bts refs/changes/63/43863/1
diff --git a/src/common/rsl.c b/src/common/rsl.c
index 88a5f17..428a3a9 100644
--- a/src/common/rsl.c
+++ b/src/common/rsl.c
@@ -394,6 +394,28 @@
return NULL;
}
+/* Find the TRX whose timeslot tn hops with the given MAIO/HSN.
+ * Returns NULL if no TRX matches, or if more than one does. */
+static struct gsm_bts_trx *trx_lookup_by_maio_hsn(struct gsm_bts *bts, uint8_t tn,
+ uint8_t maio, uint8_t hsn)
+{
+ struct gsm_bts_trx *trx, *found = NULL;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ const struct gsm_bts_trx_ts *ts = &trx->ts[tn];
+ if (!ts->hopping.enabled)
+ continue;
+ if (ts->hopping.maio != maio || ts->hopping.hsn != hsn)
+ continue;
+ if (found) {
+ LOGP(DRSL, LOGL_NOTICE, "Ambiguous MAIO=%u/HSN=%u on TS%u "
+ "(TRX%u and TRX%u)\n", maio, hsn, tn, found->nr, trx->nr);
+ return NULL;
+ }
+ found = trx;
+ }
+ return found;
+}
+
static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
const char *log_name)
{
@@ -1409,29 +1431,33 @@
* but just send the RR message to the MS as-is.
* 'trx' here is the TRX of the BCCH channel. To find the correct TRX for the IMM ASS target, we need to look up
* the ARFCN that is contained in the IMM ASS message. When frequency hopping is enabled, there will not be an
- * ARFCN, so we cannot support early-IA with frequency hopping enabled. */
+ * ARFCN, so instead we look up the TRX whose timeslot hops with the given MAIO/HSN. If this is ambiguous
+ * (different hopping groups sharing the same MAIO/HSN on the same timeslot), don't do the RR IA caching. */
if (msg->len >= sizeof(struct gsm48_imm_ass)) {
- struct gsm48_imm_ass *rr_ia = (void*)msg->data;
- if (rr_ia->chan_desc.h0.h == 0) {
- /* hopping is disabled. */
- struct gsm_bts_trx *ia_target_trx;
- uint16_t arfcn;
- arfcn = (rr_ia->chan_desc.h0.arfcn_high << 8) + rr_ia->chan_desc.h0.arfcn_low;
+ const struct gsm48_imm_ass *rr_ia = (void *)msg->data;
+ const struct gsm48_chan_desc *cd = &rr_ia->chan_desc;
+ struct gsm_bts_trx *ia_target_trx;
+ if (cd->h0.h == 0) { /* hopping is disabled */
+ uint16_t arfcn = (cd->h0.arfcn_high << 8) + cd->h0.arfcn_low;
ia_target_trx = trx_lookup_by_arfcn(&trx->bts->trx_list, arfcn);
- if (ia_target_trx) {
- /* found the ARFCN's trx */
- struct gsm_lchan *ia_target_lchan;
- ia_target_lchan = lchan_lookup(ia_target_trx, rr_ia->chan_desc.chan_nr, "Early IA check: ");
- if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) {
- /* Target lchan is not yet active. Cache the IA.
- * If a previous IA is still lingering, free it. */
- msgb_free(ia_target_lchan->early_rr_ia);
- ia_target_lchan->early_rr_ia = msg;
+ } else { /* hopping is enabled */
+ uint8_t maio = (cd->h1.maio_high << 2) + cd->h1.maio_low;
+ ia_target_trx = trx_lookup_by_maio_hsn(trx->bts, cd->chan_nr & 0x07, maio, cd->h1.hsn);
+ }
- /* return 1 means: don't msgb_free() the msg */
- return 1;
- }
+ if (ia_target_trx) {
+ /* found the target trx */
+ struct gsm_lchan *ia_target_lchan;
+ ia_target_lchan = lchan_lookup(ia_target_trx, cd->chan_nr, "Early IA check: ");
+ if (ia_target_lchan && ia_target_lchan->state != LCHAN_S_ACTIVE) {
+ /* Target lchan is not yet active. Cache the IA.
+ * If a previous IA is still lingering, free it. */
+ msgb_free(ia_target_lchan->early_rr_ia);
+ ia_target_lchan->early_rr_ia = msg;
+
+ /* return 1 means: don't msgb_free() the msg */
+ return 1;
}
}
}
--
To view, visit https://gerrit.osmocom.org/c/osmo-bts/+/43863?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: osmo-bts
Gerrit-Branch: master
Gerrit-Change-Id: I632e46cccbf1151a88d2dfaf8cb42ce2647206a5
Gerrit-Change-Number: 43863
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>